前言
最近在准备春招,刷到了JS中的主要运行机制--Event Loop,觉得它的实现思路有必要整理一下,以防忘记。关于它在浏览器上的实现,我结合了自己的理解以及示例代码,想用最通俗的语言表达出来。如果在文中出现书写错误的地方,欢迎大家留言一起探讨。
正文
关于Event Loop,宏任务,微任务的概念不再此赘述了。
概念
进入主题,我理解的浏览器的事件循环Event Loop,以及执行一个JavaScript代码的流程如下:
- 一开始整段脚本作为第一个宏任务执行;
- 执行过程中同步代码直接执行,宏任务进入宏任务队列,微任务进入微任务队列;
- 当前宏任务执行完出队,检查微任务队列,如果有则依次执行,直到微任务队列为空;如果在执行微任务的过程中,又产生了微任务,那么会加入到队列的末尾,也会在这个周期被调用执行;
- 执行浏览器 UI 线程的渲染工作;
- 执行队首新的宏任务,回到2,依此循环,直到宏任务和微任务队列都为空。
代码
1 console.log('start'); 2 3 setTimeout(() => { 4 console.log('timeout'); 5 Promise.resolve().then(() => { 6 console.log('p1') 7 }); 8 }); 9 10 Promise.resolve().then(() => { 11 console.log('p2'); 12 }); 13 14 console.log('end'); 15 16 new Promise((resolve, reject) => { 17 console.log('end2') 18 resolve('p3') 19 }).then((data) => { 20 console.log(data); 21 })
//输出结果为:
start
end
end2
p2
p3
timeout
p1
解析:
Step 1:执行全局Script代码
console.log('start'); //打印结果:start
栈:[ console ]
宏任务队列:[ ]
微任务队列:[ ]
setTimeout(() => { console.log('timeout');//将这个回调函数叫做callback1,由于setTimeout属于宏任务,所以放到宏任务队列 Promise.resolve().then(() => { console.log('p1') }); }); //打印结果:start
栈:[ setTimeout ]
宏任务队列:[ callback1 ]
微任务队列:[ ]
Promise.resolve().then(() => { console.log('p2'); //将这个回调函数叫做callback2,由于Promise属于微任务,所以放到微任务队列 }); //打印结果:start
栈:[ Promise ]
宏任务队列:[ callback1 ]
微任务队列:[ callback2 ]
console.log('end'); /* 打印结果:start end */
栈:[ console ]
宏任务队列:[ callback1 ]
微任务队列:[ callback2 ]
new Promise((resolve, reject) => { console.log('end2') //注意,这里是同步执行的!!! resolve('p3') //将这个回调函数叫做callback3,由于Promise属于微任务,所以放到微任务队列 }).then((data) => { console.log(data); }) /* 打印结果: start end end2 */
栈:[ Promise ]
宏任务队列:[ callback1 ]
微任务队列:[ callback2 callback3 ]
Step 2:全局Script代码执行完成,进入微任务队列,取出任务并执行,直至微任务队列为空。
微任务队列:[ callback2 callback3 ]
1.首先执行callback2任务:
Promise.resolve().then(() => { console.log('p2'); //将这个回调函数叫做callback2 }); //打印结果:start
end
end2
p2
栈:[ callback2 ]
宏任务队列:[ callback1 ]
微任务队列:[ callback3 ]
2.其次执行callback3任务:
new Promise((resolve, reject) => { console.log('end2') //注意,这里是同步执行的 resolve('p3') //将这个回调函数叫做callback3 }).then((data) => { console.log(data); }) /* 打印结果:start end end2 p2 p3 */
栈:[ callback3 ]
宏任务队列:[ callback1 ]
微任务队列:[ ]
Step3:微任务队列全部执行完,再去宏任务队列中取第一个任务执行。
setTimeout(() => { console.log('timeout'); //将这个回调函数叫做callback1 Promise.resolve().then(() => { console.log('p1') //将这个回调函数叫做callback4 }); });
//打印结果:start end end2
p2
p3
timeout
【注】:当执行callback1的时候又遇到了另一个promise,promise异步执行完后在微任务队列中又注册了一个callback4回调函数。
栈:[ callback1 ]
宏任务队列:[ ]
微任务队列:[ callback4 ]
Step4:当前宏任务执行完出队,检查微任务队列
setTimeout(() => { console.log('timeout'); Promise.resolve().then(() => { console.log('p1') //将这个回调函数叫做callback4 }); }); /* 打印结果:start end end2 p2 p3 timeout p1 */
栈:[ callback4 ]
宏任务队列:[ ]
微任务队列:[ ]
至此,执行完毕。
尾声
以上就是我分析的浏览器篇Event Loop的一个例子,如有错误,还请指正,谢谢!希望本次分享对你有用呀 ^_^