js事件循环机制(event loop)之宏任务/微任务
原文链接:https://blog.csdn.net/qq_33207292/article/details/102624553
1.关于js
js是单线程的,即主线程就只有一个
2.js事件循环
除了广义的同步任务和异步任务,对任务更细致费划分:
macro-task(宏任务):包括整体代码 script,setTimeout,setInterval等
micro-task(微任务):Promise的then的回调函数,process.nextTick,async 函数await下面的代码;等
js执行的时候:
第一步:js 解释器识别所有 js 代码,将同步的代码放到主线程执行;异步的代码放到Event Table(事件列表)执行。这也是第一次宏任务执行完毕!
第二步:接下来执行所有的微任务。
之后一直循环第一步,第二步,也就是常说的Event Loop(事件循环)
事件循环可以用下面这张流程图理解
为了理解来分析一段较复杂的代码:
console.log('1');
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
第一轮事件循环流程分析如下:
整体script作为第一个宏任务进入主线程,遇到console.log,输出1。
遇到setTimeout,其回调函数被分发到宏任务队列中。我们暂且记为setTimeout1。
遇到process.nextTick(),其回调函数被分发到微任务队列中。我们记为process1。
遇到Promise,new Promise直接执行,输出7。then被分发到微任务队列中。我们记为then1。
又遇到了setTimeout,其回调函数被分发到宏任务队列中,我们记为setTimeout2。
下表是第一轮事件循环宏任务结束时各Event Queue的情况,此时已经输出了1和7。
对照上述的事件循环流程图 宏任务结束之后我们接下来就开始去查看微任务中是否有任务 如果有就执行所有的微任务 这里有两个微任务process1和then1
执行process1,输出6。
执行then1,输出8。
好了,第一轮事件循环正式结束,这一轮的结果是输出1,7,6,8。那么第二轮事件循环从setTimeout1宏任务开始:
首先输出2。接下来遇到了process.nextTick(),同样将其分发到微任务队列中,记为process2。
new Promise立即执行输出4,then也分发到微任务队列中,记为then2
第二轮事件循环宏任务执行结束,执行两个微任务process2和then2。
执行process2,输出3。
执行then2,输出5。
好了,第二轮事件循环正式结束,这二轮的结果是输出2,4,3,5。那么第三轮事件循环从setTimeout2宏任务开始:
首先输出9。接下来遇到了process.nextTick(),同样将其分发到微任务队列中,记为process3。
new Promise立即执行输出11,then也分发到微任务队列中,记为then3
第三轮事件循环宏任务执行结束,执行两个微任务process3和then3。
执行process3,输出10。
执行then3,输出12。
第三轮事件循环结束,第三轮输出9,11,10,12。
整段代码,共进行了三次事件循环,完整的输出为1,7,6,8,2,4,3,5,9,11,10,12。
总结:下一个宏任务执行前会去查看微任务队列中是否有任务 有就执行所有的微任务 微任务全部执行完 再去执行下一个宏任务
在看一个列子:
setTimeout(() => {
console.log(1)
}, 1000);
setTimeout(() => {
console.log(2)
}, 500);
new Promise((resolve,reject)=>{
console.log(3)
resolve()
}).then(()=>{
console.log(4)
})
第一轮事件循环流程分析如下:
整体script作为第一个宏任务进入主线程,
遇到setTimeout,其回调函数在1000s后被分发到宏任务队列中。我们暂且记为setTimeout1。
遇到setTimeout,其回调函数在500s被分发到宏任务队列中。我们暂且记为setTimeout2。
new Promise立即执行输出3,then会立刻分发到微任务队列中,记为then
第一轮事件循环宏任务执行结束,有一个微任务then,执行得到结果4
第二轮事件循环从setTimeout2宏任务开始:
输出2,没有微任务
第三轮事件循环从setTimeout1宏任务开始:
输出1,也没有微任务
所以最后输出3,4,2,1
总结:
宏任务并不是立马放入宏任务队列的而是等到时间到了之后在放入
微任务会立马放入微任务队列中
下面出两个题供大家练习🤔~~~~~
async function async1() {
console.log('async1 start===2')
await async2()
console.log('async1 end===6')
}
async function async2() {
console.log('async2===3')
}
console.log('script start===1')
setTimeout(function () {
console.log('setTimeout==8')
}, 0)
async1();
new Promise(function (resolve) {
console.log('promise1===4')
resolve();
}).then(function () {
console.log('promise2===7')
})
console.log('script end===5')
async function async1() {
console.log('async1 start===2')
await async2()
console.log('async1 end===7')
}
async function async2() {
console.log('async2===3')
new Promise((resolve, reject) => {
console.log('promise0===4')
setTimeout(() => {
console.log('async2 promise===10')
}, 0)
})
}
console.log('script start===1')
setTimeout(function () {
console.log('setTimeout=== 9')
}, 0)
async1();
new Promise(function (resolve) {
console.log('promise1====5')
resolve();
}).then(function () {
console.log('promise2===8')
})
console.log('script end=====6')
————————————————
版权声明:本文为CSDN博主「小腰精」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_33207292/article/details/102624553