我也不知道这是个啥图
Event Loop
Event Loop 定义了浏览器执行你写的代码的顺序. 我们都知道浏览器在执行代码的时候, 并不一定按照你写的顺序来执行, 因为这里边可能存在异步执行, 而且可能有多个异步代码, 还有可能有多种异步代码. 那么当这种情况存在的时候, 浏览器就需要有一种机制, 来判断当前应当执行哪部分代码.
然后, 还需要知道 Event Loop 机制中两个任务, 第一个是宏任务 MacroTask, 第二个是微任务 MicroTask, 还有一个叫执行栈的东西. Event Loop 的机制就是先让执行栈执行完宏任务队列中的所有任务, 然后再执行微任务队列中的所有任务, 完了继续循环.
执行栈: 所有的 JS 代码都会被放到执行栈中依次执行.
宏任务: 简单点说, 就是一串 JS 代码, 但是被划分为了宏任务. 哪些会被划分为宏任务呢? 包括
script 标签中代码
setTimeout setInterval I/O UI 渲染 postMessage 等(并没有归纳完). 宏任务可以继续产生宏任务 / 微任务.
微任务: 同理, 也是一串被划分为微任务的 JS 代码. 包括
Promise 中的 resolve/reject
async/await process.nextTick 等(并没有归纳完). 同样, 微任务也可以继续产生宏任务 / 微任务.
废话少说, 赶紧聚个例子:
- // 先来个简单点的
- console.log("start");
- setTimeout(_ => console.log("setTimeout"), 0);
- console.log("end");
- // start
- // end
- // setTimout
- // 解释不? 算了不解释了
- // 第二个例子, 还是简单点
- console.log("start");
- setTimeout(_ => console.log("setTimeout"), 0);
- new Promise(resolve => {
- console.log("new Promise");
- resolve("promise then");
- }).then(res => console.log(res));
- console.log("end");
- // start
- // new Promise
- // end
- //promise then
- // setTimeout
- // 解释不? 还是解释哈嘛......
- /* 是弄个子的
- 1. 执行栈会首先去拿宏任务列表中的代码块来执行, 此时只有 script 标签代码, 所以就拿过来执行咯哟
- 2. 执行第一句, 输出 start
- 3. 执行第二句, 遇到了 setTimeout, 此时会将其回掉任务加入到下一轮的宏任务中
- 4.new Promise 中的代码直接执行(为什么直接执行, 请看 Promise 相关知识),
- 输出 new Promise, 完了遇到了 resolve 代码, 此时会将其回掉任务加入到下一轮微任务中
- 5. 输出 end, 此时, 本轮宏任务执行完毕, 开始执行微任务
- 6. 由上可知, 微任务中第一条 (也仅此一条) 是 resolve 的回掉, 所以拿出来执行, 输出 promise then
- 7. 微任务执行完了, 再次执行宏任务, 也从第一条开始, 输出 setTimeout
- 8.done!!!
- */
- // 第三个例子, 不难, 只是多增加了两位新客人而已
- console.log("start");
- setTimeout(_ => console.log("setTimeout"), 0);
- new Promise(resolve => {
- console.log("new Promise");
- setTimeout(_ => console.log("new Promise setTimeout"), 0);
- resolve("promise then");
- }).then(res => console.log(res));
- async function asyncFunc1() {
- console.log("asyncFunc1 start");
- await asyncFunc2();
- console.log("asyncFunc1 end");
- }
- async function asyncFunc2() {
- console.log("asyncFunc2");
- }
- asyncFunc1();
- console.log("end");
- /* 先补充哈 async/await 的只是哈 */ /* 开始补充... */ /* 补充完毕 */
- // 输出
- //start
- //new Promise
- //asyncFunc1 start
- //asyncFunc2
- //end
- //promise then
- //asyncFunc1 end
- //setTimeout
- //new Promise setTimeout
- /* 不用解释了, 只要晓得 async/await 而且李杰了上一个例子, 那就没问题了 */
- // 第四个例子
- console.log("start");
- setTimeout(function setTimeoutCallbackFunc1() {console.log("setTimeout")}, 0);
- new Promise(resolve => {
- console.log("new Promise");
- setTimeout(function setTimeoutCallbackFunc2() {console.log("new Promise setTimeout")}, 0);
- resolve("promise then");
- }).then(function promiseThenCallbackFunc1(res) {console.log(res)});
- async function asyncFunc1() {
- console.log("asyncFunc1 start");
- await asyncFunc2();
- console.log("asyncFunc1 end");
- }
- async function asyncFunc2() {
- console.log("asyncFunc2");
- return new Promise(resolve => {
- setTimeout(function setTimeoutCallbackFunc3() {
- console.log("asyncFunc2 promise");
- resolve();
- }, 0);
- })
- }
- asyncFunc1();
- console.log("end");
- // 这又输出什么呢? 这个可以说一哈, 至于输出啥子, 稍等哈, 我复制到浏览器执行哈...
- // 执行完了, 输出
- // start
- // new Promise
- // asyncFunc1 start
- // asyncFunc2
- // end
- // promise then
- // setTimeout
- // new Promise setTimeout
- // asyncFunc2 promise
- // asyncFunc1 end
- /* 终于打完了 */ /* 虽然我在浏览器中执行后照到打的, 但是我能解释清楚 */ /* 开始装... */
为了形象点, 画图又不会, 咋个搞呢? 搞个都看得懂的
- macList = [] // 宏任务队列
- micList = [] // 微任务队列
比如: macList = [task1, task2, task3, task4, task5, ...]
好了, 开始装了...
首先, 执行栈还是会先执行宏任务, 那就去宏任务列表中取, 此时的 macList = [script], 所以取出 script 执行, macList = [].
输出 start.
遇到 setTimout, 将回掉加入到宏任务列表中, macList = [setTimeoutCallbackFunc1].
执行 new Promise 代码, 输出 new Promise, 然后遇到 setTimeout, 加入到红任务列表中, macList = [setTimeoutCallbackFunc1, setTimeoutCallbackFunc2], 然后又遇到 resolve, 将其回掉加入到微任务列表, micList = [promiseThenCallbackFunc1].
(请先预备 async/await 知识)执行 asyncFunc1 函数, 则输出 asyncFunc1 start, 遇到 await asyncFunc2(), 则先执行函数, 输出 asyncFunc2, 然后返回了一个 new Promise,new Promise 中的代码回立马执行, 遇到了 setTimeout, 加入到宏任务队列, macList = [setTimeoutCallbackFunc1, setTimeoutCallbackFunc2, setTimeoutCallbackFunc3], 而后返回到 asyncFunc1 中, 后边的代码会全部被封装到 then 中, 直到 asyncFunc2 中 resolve 才会被执行.
第 5 点结束, asyncFunc1 执行也就结束, 然后输出 end.
至此, 本轮宏任务结束, 输出了 start, new Promise, asyncFunc1 start, asyncFunc2, end. 开始执行微任务.
然后开始微任务列表挨个执行. 此时 micList = [promiseThenCallbackFunc1], 取出 promiseThenCallbackFunc1 执行, 输出 promise then. 微任务队列执行完毕, 再次执行宏任务.
此时宏任务列表 macList = [setTimeoutCallbackFunc1, setTimeoutCallbackFunc2, setTimeoutCallbackFunc3]. 挨个取出执行.
执行 setTimeoutCallbackFunc1, 输出 setTimout
执行 setTimeoutCallbackFunc2, 输出 new Promise setTimout
执行 setTimeoutCallbackFunc3, 输出 asyncFunc2 promise, 但此时又遇到 resolve, 此时会将 await asyncFunc2()后的代码当作回掉, 加入到微任务列表中 micList = [console.log("asyncFunc1 end")]. 宏任务队列又执行完毕, 又开始执行微任务.
此时微任务 micList = [console.log("asyncFunc1 end")], 取出执行, 输出 asyncFunc1 end. 此时全部执行完毕.
done!!!!
理解得不深, 如有错误, 赶紧指正, 非常感谢!!!
来源: http://www.jianshu.com/p/2cf1263b4c30