关于JS执行机制这一块内容,一直是自己比较难以理解的知识点,结合自己看的资料与代码实践,写一篇总结。
首先,我们熟知JS是单线程语言,再同一时间只能做一件事情。所以JS是按着语句顺序依次执行下来的。
let a = 1
console.log(a)
let b = 2
console.log(b)
//依次输出1 2
之后,接触了很多知识之后,我们认识到了两个定时器setTimeout和它的兄弟setInterval。这一段代码中,按着之前的逻辑应该依次输出1 2 3。
但是实际情况的输出为1 3 2。
console.log(1)
setTimeout(() => {
console.log(2)
}, 1000)
console.log(3) //1 3 2
在这个时候我们就要引入两个概念: 同步任务和异步任务。
- 同步任务: 在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务
- 异步任务: 不进入主线程,而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行
而上述的setTimeout和setInterval就是异步任务。那整个执行机制就可以用下面的图片表示。
图片用文字表达就是:
- 当任务进入执行栈,首先会判断是同步任务还是异步任务
- 当为同步任务的时候进入主线程直接执行;当为异步任务的时候,进入Event table注册函数,函数注册完成之后推入Event queue,等待主线程空闲时执行。
- 一旦主线程空闲,就会从任务队列中取对应的函数,进入主线程
- 然后重复上述过程,称之为事件循环
实例练习:
console.log(1)
setTimeout(() => {
console.log(2)
}, 5000)
console.log(3)
setTimeout(() => {
console.log(4)
}, 1000) //1 3 4 2
按着上述理论,这段代码的执行过程应该如下:
- 整段代码进入主程序
- console是同步任务,直接输出
- setTimeout是异步任务,进入event table中注册函数
- console是同步任务,直接输出
- setTimeout是异步任务,进入event table中注册函数。此时,在event table中有两个setTimeout在注册函数,然而第二个setTimeout只需要等待1000ms完成注册,第一个则需要等待5000ms完成注册,所以第二个setTimeout比第一个先推入Event queue。所以当第二个console执行完毕的时候,是第二个setTimeout先进入主线程执行。
- 综上所述,最后的输出结果为1 3 4 2
setTimeout这个函数,是经过指定时间后,把要执行的任务加入到Event Queue中,又因为是单线程任务要一个一个执行,如果前面的任务需要的时间太久,那么只能等着,导致真正的延迟时间远远大于设置时间。对于执行顺序来说,setInterval会每隔指定的时间将注册的函数置入Event Queue,如果前面的任务耗时太久,那么同样需要等待。
接着,我们认识了Promise这个异步函数。打开了新世界大门。
我们又对任务有了更精细的区别宏任务和微任务。
- 宏任务: 整段代码、setTimeout、setInterval
- 微任务: promise、process.nextTick(callback)
按着宏任务微任务来说,执行机制就应该如下图。
实例练习:
setTimeout(function() {
console.log(1);
}, 4000)
new Promise(function(resolve) {
console.log(2)
resolve()
}).then(function() {
console.log(3)
})
console.log(4) //2 4 3 5 1
setTimeout(function() {
console.log(5);
}, 1000)
按着上述理论,这段代码的执行过程应该如下:
- 整段代码作为宏任务开始执行
- 遇到宏任务setTimeout,加入宏任务Event queue(注册过程同上)
- 遇到new Promise立即执行,then函数推入微任务Event queue
- 遇到console立即执行
- 遇到宏任务setTimeout,加入宏任务Event queue(注册过程同上),由于它完成注册的时间早于第一个setTimeout,会成为第二个执行的宏任务
- 第一个宏任务执行完毕,检查微任务Event queue中包含任务,执行
- 第一轮事件循坏结束,开始第二轮事件循环,直至结束。
事件循环(Event Loop)就是JavaScript的执行机制。
这篇文章思路来源于这一次,彻底弄懂 JavaScript 执行机制,也是自己对学习完这个知识点的一个总结。