Javascript的运行时机

JavaScript在网页中的三大生存现场与运行本质 JavaScript不是孤立的编程语言,而是嵌入网页生命周期的动态行为引擎。它依托HTML解析、用户交互和页面加载三大运行时场景,通过DOM操作、事件驱动和异步调度实现真实交互。理解其在FCP与DOM Content Loaded之间的执行时机,掌握js三级联动、javascript:void(0)、js反爬实战等典型用例背后的运行逻辑,是构建高性能、可维护前端应用的基础。本文从浏览器渲染流水线、V8引擎工作流到Bun等新型JS运行时演进,揭示JS如何在真实网页中‘呼吸’与‘响应’,帮助开发者建立代码与界面 阅读详情

Javascript何时开始运行,是一个看起来简单,但其实比较复杂而重要的事情。它关系到:

  1. 页面的加载速度。
  2. Javascript如果用来处理DOM/CSS,则需要处理先后次序和由之引起的依赖问题。
  3. Javascript之间可能存在依赖。在一些复杂的页面中,某些Javascript的往往是由另一些Javascript加载进来的。
  4. User script,extension和bookmarklet存在的情况下,Javascript的执行时间更加不确定。

 

当浏览器取回一个HTML文件的文本后,它始终按顺序解析这个文本,即最先处理<head>,然后是<body>。一个元素结点解析完毕之前,不会开始对下一个结点的解析。解析的工作包括,处理对外部资源的下载,比如图片,外部javascript和样式表的下载;构造DOM树;结合样式表渲染要呈现给最终用户的内容。对图片的下载是异步下载,因为图片的内容并不影响DOM树的构造;只要事先知道图片的大小,则对图片的渲染也可以留到图片完全下载后处理。由于没有样式表则无法进行渲染,所以对样式表的下载应该放在最前面处理,也即样式表标签应该放在页面的最前面。对javascript尽管异步/并行下载是可能的,但是由于它们可能包含改变页面内容和结构的语句(document.write()),因此浏览器对javscript都是同步下载,即任何时候都只处理一个javascript的下载。为了加快javascript的加载速度,一些ajax框架使用了异步加载器的技术,因此,在使用了javascript框架的情况下,上述假定则不一定成立。

最重要的页面事件是window.onload。当该事件发生时,浏览器保证页面的全部元素已经加载完毕,并且完全可以被操作。但是,在使用了ajax框架的情况下,由于使用了异步加载技术,上述假定不一定成立。比如在使用dojo的案例中,当window.onload事件发生时,尽管可以确保dojo这个scopename可以使用,但是如果代码中调用了dojo.require以请求其它javascript的话,这些javascript并不一定也加载完毕。因此,应该使用框架的相应代码,比如dojo.ready, YUI.available来保证模块之间的依赖已经解决。

由于浏览器对javascript标签采取阻塞式的处理模式,因此,如果ajax框架代码的核心库文件是静态链接进页面的,则任何在该标签之后的javascript代码都可以使用该核心库提供的功能。但是,如果ajax框架代码的核心库文件是由user script(关于user  script,参见Greasemonkey或者trixie)或者bookmarklet创建的script标签引入的,此时往往会出现一个问题,以dojo为例。当我们在用户脚本中把初始化代码放到dojo.ready()调用中时,常常可能遇到dojo is not defined错误,原因是,用户脚本在通过DOM API向页面插入一个<script src="http://.../dojo.js"/>标签后,很可能立即就调用dojo的某些功能。尽管该标签插入之后浏览器就立即开始下载和解析dojo.js,但是多数情况下,用户脚本的代码会先于dojo.js处理完毕后即开始执行。此时的处理办法是在window.onload的回调函数里执行需要使用dojo的代码。

window.onload的问题

前面已经提到,window.load事件将会在页面的所有元素都加载完毕后发生,即使是在使用用户脚本的情况下也是如此。但问题是,如果页面包含较多图片,则javascript的执行会太晚。如果页面中存在javascript构建的菜单,这将会对用户体验造成不好的影响。事实上,如果javascript本身不涉及到图片处理的话,则完全不必等到这么晚才执行。Dean Edwards给出了一个解决方案:

// Dean Edwards/Matthias Miller/John Resig

function init() {
    // quit if this function has already been called
    if (arguments.callee.done) return;

    // flag this function so we don't do the same thing twice
    arguments.callee.done = true;

    // kill the timer
    if (_timer) clearInterval(_timer);

    // do stuff
};

/* for Mozilla/Opera9 */
if (document.addEventListener) {
    document.addEventListener("DOMContentLoaded", init, false);
}

/* for Internet Explorer */
/*@cc_on @*/
/*@if (@_win32)
    document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
    var script = document.getElementById("__ie_onload");
    script.onreadystatechange = function() {
        if (this.readyState == "complete") {
            init(); // call the onload handler
        }
    };
/*@end @*/

/* for Safari */
if (/WebKit/i.test(navigator.userAgent)) { // sniff
    var _timer = setInterval(function() {
        if (/loaded|complete/.test(document.readyState)) {
            init(); // call the onload handler
        }
    }, 10);
}

/* for other browsers */
window.onload = init;

这个方案可以包装得更易用一点,我们使用闭包来构造一个functor,将用户的初始化部分作为一个callback传入进去:

MYMODULE.ready = function(fnCallback){
    var init = function(cb){
        return function(){
            // kill the timer
            if (_timer) clearInterval(_timer);
        
             // do stuff
             cb();
        }
    }(fnCallback);

    /* for Mozilla/Opera9 */
    if (document.addEventListener) {
        document.addEventListener("DOMContentLoaded", init, false);
    }
    
    /* for Internet Explorer */
    /*@cc_on @*/
    /*@if (@_win32)
        document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
        var script = document.getElementById("__ie_onload");
        script.onreadystatechange = function() {
            if (this.readyState == "complete") {
                init(); // call the onload handler
            }
        };
    /*@end @*/
    
    /* for Safari */
    if (/WebKit/i.test(navigator.userAgent)) { // sniff
        var _timer = setInterval(function() {
            if (/loaded|complete/.test(document.readyState)) {
                init(); // call the onload handler
            }
        }, 10);
    }
    
    /* for other browsers */
    window.onload = init;
}

这样调用时只需要先定义一个回调函数,再调用MYMODULE.ready:
function appInit(){
    // perform all app init here. It'll executed while the DOM is ready
}

MYMODULE.ready(appInit);

与Edwards的方案不同,包装后的方案去掉了对重复调用初始化的检查,原因在于,每次调用MYMODULE.ready时都会生成一个新的闭包,这个闭包中,arguments.callee.done的值总是'undefined'。再次调用MYMODULE.ready时,由于新生成的闭包跟以前生成的闭包引用的不是同一对象,所以前面对arguments.callee.done的赋值也不会影响到新的闭包,从而无法防止多次调用初始化。解决这个问题的方法之一是在MYMODULE这一级加入模块级全局变量并在闭包init中判断/修改其值。另一个方法是将MYMODULE设计成singleton模式。

事件循环 Microtasks (微任务) 的运行时机——从接受知识到探索v8源码 从两年前被动接受知识 "当浏览器JS引擎调用栈弹空的时候,才会执行 Microtasks 队列",到两年后主动深入探索源码后了解到的 "当 V8 执行完调用要返回 Blink 时,由于 MicrotasksScope 作用域失效,在其析构函数中检查 JS 调用栈是否为空,如果为空就会运行 Microtasks。两年的时间过去了,在上周整理笔记的时候,我开始质疑这一个知识,"当浏览器 JS 引擎调用栈弹空的时候,才会执行 Microtasks 队列"。答案是否定的,Microtasks 的运行时机是由。 阅读详情

相关推荐

从零开始安装pytorch(包含GPU和CPU版本的安装)

Pytorch是。

qiaoxinyu1989的博客 8万+

浏览器是如何渲染页面的?

浏览器是如何渲染页面的?

qq_50109437的博客 528

人大金仓集群部署(主备)

4.2 上传安装包镜像和授权文件到install目录下并授权。1、复制系统脚本到/opt/kingbase目录下(主节点)4.2 修改cluster_install.sh。回车进行下一步,直到出现以下界面,回复Y键回车。三、安装kingbase客户端段(都要安装)install目录作为安装包具体存放目录。4.1 修改install.conf文件。2、复制授权文件到安装目录下(主节点)3、修改ssh参数(节点都要配置)5、安装kingbase客户端。二、基本环境配置(都要配置)6、数据库集群安装(主节点)

edutech_wang的博客 1996

delphi 调用浏览器内核_浏览器渲染原理流程

前言浏览器的内核是指支持浏览器运行的最核心的程序,分为两个部分的,一是渲染引擎,另一个是JS引擎。渲染引擎在不同的浏览器中也不是都相同的。目前市面上常见的浏览器内核可以分为这四种:Trident(IE)、Gecko(火狐)、Blink(Chrome、Opera)、Webkit(Safari)。这里面大家最耳熟能详的可能就是 Webkit 内核了,Webkit 内核是当下浏览器世界真正的霸主。本文我...

weixin_39602637的博客 501

从零开始:用YOLOv8-Pose实现实时人体姿态检测(附完整代码)

本文提供了一份从零开始的完整实战指南,详细介绍了如何使用YOLOv8-Pose构建实时人体姿态检测系统。内容涵盖环境搭建、数据准备、模型训练与调优,以及高性能部署和进阶应用开发,并附有可直接运行的代码示例,帮助开发者快速掌握Pose Estimation技术并将其应用于实际项目。

h6i7j8的博客 621

Epicor ERP 界面新增客制化字段操作方法

我发现国内对于epicor这个erp软件的教程非常少,所以录制一些我实际遇到的需求,整理了实现过程,提供给大家参考。

cqxianggang的专栏 413

JS的执行时机(探究6个6问题)

大家好,这里是阿凉,今天给大家讲一下JS的执行时机。以及6个6问题。

zymtasd0_的博客 436

《AgentScope-Java 深入浅出教程》第8章 工具高级特性

掌握工具组、预设参数、执行上下文等高级特性。

步子哥的博客 266

JS函数的执行时机

函数的要素,每个函数都有以下这些东西: 1.调用时机 2.作用域 3.闭包 4.形式参数 5.返回值 6.调用栈 7.函数提示 8.arguments (除了箭头函数) 9.this (除了箭头函数) 今天主要讲解 调用时机。 一.调用时机 时机不同结果不同 fn不加()永远不会调用 例1 let a=1 function fn(){ console.log(a) } a=2 //a更新到2了 fn() 问打印出多少? 2 例2 let a=1 function fn(){ cons.

baidulixueqin的博客 574

基于物联网设计温室水培系统(NBIOT+华为云IOT)_338

本项目设计并实现了一套基于物联网的温室水培系统。系统以STM32F103RCT6单片机为核心控制器,结合SHT30温湿度传感器、SGP30二氧化碳传感器、BH1750光照传感器及液位检测传感器等硬件,实现对温室内环境参数的实时采集。系统支持自动和手动两种控制模式,能够根据传感器数据自动控制补光灯、通风风扇、遮光卷帘、降温水帘及营养液补充电机。通过NBIoT模块,系统可将采集的数据通过MQTT协议上传至华为云IOT平台,用户可通过Android手机APP或Windows上位机进行远程监控与控制。

414

Unity之Timeline教程

Unity Timeline是Unity的一种时间轴编辑器工具,用于制作和管理游戏中的动画、剧情以及事件触发。它提供了直观的界面,使得开发者可以通过拖放操作轻松创建和编辑时间轴。Activation Track:用于控制物体的激活状态。可以在轨道上添加关键帧,控制物体的激活和非激活状态。Animation Track:用于处理物体的动画。可以在此轨道上添加关键帧,编辑物体的动画状态。Audio Track:用于处理场景中的音频。可以管理音频的播放、暂停、淡入淡出等操作。

TxNet 9443

dom加载和js执行的时间先后

浏览器的渲染和操作顺序如下: html解析完毕外部脚本和样式表加载完毕脚本在文档内解析并执行html dom完全构造起来涂攀和外部内容加载 (以上内容来源于javascript>一书) 对于外部js文件来说,先加载外部js文件,然后执行js代码,DOM加载并不能保证在其执行前加载完毕。 而行内js,由于按照顺序执行,在js代码执行时,位于行内js之前的元素,其对应的dom节

qfgg3的专栏 6846

17、非线性动力学特征在情感语音与食管语音分析中的应用

本文探讨了非线性动力学特征在情感语音与食管语音分析中的应用。在情感语音识别中,选取Hurst指数、相关维数和Lempel-Ziv复杂度等混沌特征结合统计量,通过神经网络实现了中性、恐惧和愤怒情感的高效分类,全局成功率高达93.78%。在食管语音分析中,针对其缺乏明显周期性的问题,提出基于改进自相关方法的基频测量流程,包括包络计算、平滑与峰值细化,并对基频的物理意义提出思考。研究展示了两类语音在特征表现与技术方法上的差异,展望了其在客服、安全、医疗康复等领域的应用前景,并指出了未来在特征拓展、算法优化和发声机

sunny的博客 76

客户端js运行时机

在浏览器中js脚本运行为何会阻塞文档解析?如何改变js脚本运行时机会?defer和async属性又有什么区别呢

qq_42676176的博客 205

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

javascript加载与运行的时机

最近在看一本书《高性能javascript》,觉得很有感触,以前都没有注意这些,看了之后拿出来与大家分享一下   事实上,大多数浏览器使用单进程处理UI更新和javascript运行多个任务,而同时只能有一个任务被执行,这样javascript的加载和运行就被阻塞了。我们来看看下面一个简单的例子 Script Example Hello world!

兰华 1519

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Javascript关于promise的学习和运行时机

Javascript关于promise的学习和运行时机

bangrenzhuce的博客 1945

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

JS在页面加载之后运行

通用的页面加载后再运行JS有两种方式:1、在DOM加载完毕后,页面全部内容(如图片等)完全加载完毕前运行JS。 2、在页面全部内容加载完成(包括引用文件,图片等)之后再加载JS 1、在DOM加载后,全部内容加载前运行 这种方式在同一文件中可以运行多个且不会覆盖。 由于在$(document).ready()方法只要DOM就绪就会被执行,因此可能此时元素的关联文件未下载完。例如与...

weixin_30662539的博客 282

js立即执行函数_JS 函数的执行时机

首先我们来看一段代码,通过这段代码来理解 JS 函数的执行时机。打印出的结果为6个6,而不是0~5要理解上面这段代码,我们需要先简单了解以下几个知识点:JavaScript 是单线程语言,也就是同一时间只能做一件事。为什么 JavaScript 是单线程,因为它的主要用途是与用户互动,以及操作 DOM,这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假设 JavaScript 同时有两个...

weixin_39564617的博客 422

网页javascript加载不出_JavaScript执行顺序

通过优锐课核心java学习笔记中,我们可以看到,码了很多专业的相关知识, 分享给大家参考学习。确定什么JavaScript将在何时运行使用JavaScript设计网页需要注意代码的显示顺序以及是否将代码封装到函数或对象中,所有这些都会影响代码的运行顺序。JavaScript在网页上的位置由于页面上的JavaScript是根据某些因素执行的,因此,请考虑将JavaScript添加到网页的位置和方式。...

weixin_39557419的博客 1639

Uncaught TypeError: Cannot read property 'replace' of null

你的JS运行的时候你的页面还没有加载完成,所以你的JS代码找不到你的页面元素,就会抛出这个问题

Azhangyuaner的博客 4205

js里面log打印_JS 函数的执行时机

函数调用时机对结果的影响函数需要执行let a =1 function fn (){ console.log(a) } //没有调用函数,无法打印 let a =1 function fn (){ console.log(a) } fn() //打印出1 注意调用时机let a = 1 function fn (){ console.log(a) } a = 2 fn() //打印...

weixin_39968436的博客 801

html页面交互及JS(JavaScript)使用方法

html页面交互及JS(JavaScript)使用方法

晴天的博客 338

JavaScript复习01 js概念/js组成/js运行环境/在body和head使用的区别/js特点/js注释/关键字与保留字/数据类型/引用数据类型/类型判断

js是一门函数优先(函数当成变量来用),具有原型编程(不使用class创建object)的需要解释器解析执行。

qq_53642101的博客 250

原生js打印得不出结果,是因为js引入位置不对

query的初始化方法,经过处理的,所以放在程序的哪里都可以; 原生js则需要等页面元素(div等)加载完后才能执行js。

weixin_42132833的博客 434

转载 JavaScript的函数声明与函数表达式的区别

1)函数声明(Function Declaration); // 函数声明 function funDeclaration(type){ return type==="Declaration"; }    2)函数表达式(Function Expression)。 // 函数表达式 var funExpre...

weixin_30567471的博客 58

JS的基本使用和语法

JavaScript 1.主要内容 )2.JavaScript 3.基础语法 )4.JS事件 》5.8OM对象 )6.DOM对象 )7.JS表单 2.1.2.开发工具 浏览器:Chrome ,开发工具:HbuildII 进入浏览器控制台Console:F12 控制台的作用: console对象代表浏览器的JavaScript控制台,用来运行JavaScript命令,常常用来显示网页运行时候,错误信息。Elements用来调试网页的html和css代码. 2.2.基本用法 JS需要和HT...

m0_62052122的博客 6993
上一篇: dojo.Deferred
下一篇: Aptana 3 and say bye to others!
yaaron
博客等级 码龄19年 7粉丝 30原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值