Javascript运行机制理解总结
首先,我想说一下Javascript的装载和执行。
通常来说,浏览器对于Javascript的运行有两大特性:
1)载入后马上执行,
2)执行时会阻塞页面后续的内容(包括页面的渲染、其它资源的下载)**。于是,如果有多个js文件被引入,那么对于浏览器来说,这些js文件被被串行地载入,并依次执行。
因为javascript可能会来操作HTML文档的DOM树,所以,浏览器一般都不会像并行下载css文件并行下载js文件,因为这是js文件的特殊性造成的。
所以,如果你的javascript想操作后面的DOM元素,基本上来说,浏览器都会报错说对象找不到。因为Javascript执行时,后面的HTML被阻塞住了,DOM树时还没有后面的DOM结点。所以程序也就报错了。
有没有办法实现只加载不立即执行,后续按需执行呢?
http://www.linjunlong.com/p/1156.html 这里有一种方案。
下面说说具体执行:
- 栈和队列
文章图片
image.png
可以看出:
所有的代码都要通过函数调用栈中调用执行。
当遇到前文中提到的APIs的时候,会交给浏览器内核的其他模块进行处理。
任务队列中存放的是回调函数。
等到调用栈中的task执行完之后再回去执行任务队列之中的task。
- 整个事件循环机制包含两种事件队列
(function test() {
/*开始执行本次macro-task*/
setTimeout(function() {console.log(4)}, 0);
----作为一个macro-task,将其回调函数放入自己的队列之中。
new Promise(function executor(resolve) {
console.log(1);
---- 立即执行
for( var i=0 ;
i<10000 ;
i++ ) {
i == 9999 && resolve();
}
console.log(2);
---- 立即执行
}).then(function() {
console.log(5);
---micro task queue
});
console.log(3);
---- 立即执行
})()
macro-task包括:script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering。
【Javascript运行机制理解总结】micro-task包括:process.nextTick, Promises, Object.observe, MutationObserver
事件循环的顺序是从script开始第一次循环,随后全局上下文进入函数调用栈,碰到macro-task就将其交给处理它的模块处理完之后将回调函数放进macro-task的队列之中,碰到micro-task也是将其回调函数放进micro-task的队列之中。直到函数调用栈清空只剩全局执行上下文,然后开始执行所有的micro-task。当所有可执行的micro-task执行完毕之后。循环再次执行macro-task中的一个任务队列,执行完之后再执行所有的micro-task,就这样一直循环。
总结
- 不同的任务会放进不同的任务队列之中。
- 先执行macro-task,等到函数调用栈清空之后再执行所有在队列之中的micro-task。
- 等到所有micro-task执行完之后再从macro-task中的一个任务队列开始执行,就这样一直循环。
- 当有多个macro-task(micro-task)队列时,事件循环的顺序是按上文macro-task(micro-task)的分类中书写的顺序执行的。
https://zhuanlan.zhihu.com/p/26229293
推荐阅读
- JavaScript|JavaScript 如何解决数字计算的精度问题
- 区块链-侧链理解
- 活动3|活动3 找异同
- Spring|Spring AOP之原理解析(三)
- 深入理解js中的立即执行函数(function(){....})
- JavaScript习题(一)
- 深入理解Eureka覆盖状态(九)
- ios|ios block的完全理解循环引用
- JavaScript|JavaScript 的new操作做了什么()
- 好的思考应当能够帮助别人加深对现实的理解