JS 是一门单线程语言 (换句话说: 一个时间内我只能做一件事), 异步操作都是放到事件循环队列中, 等待主执行栈来执行
JS 是如何执行的 (执行顺序)
●从上往下, 一行一行执行
●如果中间的某一行书写有误, 那么程序在运行到这一行会报错并停止向下继续运行
●先把所有的同步代码执行完毕, 然后再开始执行异步代码
EventLoop 是什么
其实就是一种执行方式, 当主线程的任务执行完毕后, 会通过轮询, 轮询事件队列(也有人叫做回调队列)当中的任务的方式去执行任务, 如果事件队列中的任务为空, 会一直轮询, 通过事件轮询推入主线程
EventLoop 的规则是什么
● 从宏任务开始
●每执行完毕一个宏任务, 就会清空一次微任务队列(不管微任务队列有多少任务, 都执行完毕)
●然后再次执行一个宏任务
●循环往复, 直到所有任务队列全都清空
宏任务宇微任务是什么
●在 JS 中, 代码分为了两种, 同步和异步
●异步任务中也分为了两种, 宏任务与微任务
○宏任务: 'script 整体代码, setTimeout, setInterval 等...'
○微任务: 'Promise.then(), process.nextTick(NodeJs), MutationObserver(H5新特性)...'
文章底部扫码,免费领取前端资料大礼包!
案例分析
console.log(1)
setTimeout(() => console.log(2), 0)
Promise.resolve().then(() => console.log(3))
console.log(4)
复制代码
●具体流程
1.根据 EventLoop 的规则, 从宏任务开始, 因为 script 就算一个宏任务, 所以此时会先将它内部的所有 同步代码执行完毕
a. 代码从上往下执行, 在第一行遇到了一个 console.log(1), 属于同步代码, 直接执行 (打印1)
b.向下执行中, 遇到一个 setTimeout 推入到 宏任务队列
c.向下继续执行, 遇到一个 promise.then(), 推入到微任务队列
d.最后遇到了一个 console.log(4), 属于同步代码, 直接打印 (打印4)
2. 根据 EventLoop 的规则, 此时执行完毕一个 宏任务, 那么会清空微任务队列
a.微任务队列中只有一个 promise.then, 内部的代码为 console.log(3)
b.所以清空完毕微任务队列后, 控制台多了一个 打印 3
3. 根据 EventLoop 的规则, 此时会继续执行下一个宏任务
a.目前宏任务队列中的任务为 setTimeout, 内部的代码为 console.log(2)
b.所以执行完 当前宏任务后, 控制台多了一个 打印 2
4. 根据 EventLoop 的规则, 此时会清空微任务队列, 但是此时微任务内没有任何任务
5. 根据 EventLoop 的规则, 此时会查看宏任务队列, 但是此时宏任务内也没有任何任务
6. 程序到此已全都执行完毕
7. 最终的打印结果: '1, 4, 3, 2'
如果在宏任务执行过程中又开启了一个微任务如何执行?
●代码
console.log(1)
setTimeout(() => {
console.log(2)
Promise.resolve().then(() => {
console.log(3)
})
})
new Promise((resolve, reject) => {
console.log(4)
resolve(5)
}).then((data) => {
console.log(data);
return 6;
}).then((data)=>{
console.log(data)
})
setTimeout(() => {
console.log(7);
})
console.log(8);
复制代码
文章底部扫码,免费领取前端资料大礼包!
● 执行流程
一、执行 script 中的所有代码
1、console.log(1); 同步任务 直接打印
2、setTimerout; 异步任务, 推入宏任务队列
3、new Promise 中的代码属于同步任务, 但是 后续的 then 属于异步任务; 所以会执行 console.log(4); 并推入 then 到微任务队列
4、setTimerout; 异步任务, 推入宏任务队列 (在此之前已经有一个了)
5、console.log(8); 同步任务直接打印
6、此时控制台打印: '1, 4, 8'
二、根据规则, 此时执行完毕一个宏任务, 所以会去清空微任务队列中的任务
1、此时微任务队列中的是 之前的 promise 的 then 方法, 因为 promise中 resolve的值为 5, 所以此时打印的值是 5
2、这个 then 方法执行完毕会 return 一个 6, 所以后续的 then 方法会继续执行, 所以打印的是 6
3、此时控制台打印: '5, 6'
三、根据规则, 此时会微任务队列已清空, 所以会执行下一个宏任务
1、此时会执行第一个 setTimetou
2、内部代码第一个为 console.log(2), 所以会直接打印
3、后续的代码为一段 promise, 注意: "此时会将这个promise推入微任务队列中"
4、此时控制台打印: '2'
四、执行完毕一个宏任务后, 再次清空微任务队列
1、此时就只有第三步中的 promise 这一个微任务了
2、这个微任务执行时会打印 3
3、此时控制台打印: '3'
五、微任务队列清空完毕后继续执行宏任务
1、此时就只剩下最后一个 setTimeout 了
2、执行内容为 console.log(7)
3、此时控制台打印: '7'
六、最终的打印结果: '1, 4, 8, 5, 6, 2, 3, 7'
如果上面的文章看着比较枯燥,点击下面的链接直接观看:
千锋教育JavaScript全套视频教程(10天学会Js,前端javascript入门必备)
也可以扫码直接观看视频哦!绝对的干货满满,更多精彩视频B站搜索“千锋教育”