同步和异步任务分别进入不同的执行”场所”,同步的进入主线程(执行栈),异步的进入 Event Table 并注册函数。当指定的事情完成时,Event Table 会将这个函数移入 Event Queue。
主线程内的任务执行完毕为空,会去 Event Queue 读取对应的函数,进入主线程执行。上述过程会不断重复,也就是常说的 Event Loop(事件循环)。
这里异步任务的 Event Queue 分两种情况的,即宏任务 (macrotask) 和微任务 (microtask),当主线程任务完成为空去 Event Quenu 读取函数的时候,是先读取的微任务,当微任务执行完毕之后,才会继续执行宏任务。
综上事件循环为:同步 > 异步 微任务 > 宏任务
那么微任务和宏任务都有什么呢,简单总结下就是:
宏任务:整体代码 script,setTimeout,setInterval
微任务:原生 Promise 相关,process.nextTick
1 | async function async1() { |
答案:
1 | "start" |
分析:
- 主函数打印”start”。
- 执行 setTimeout,将 setTimeout 回调函数放入异步宏任务队列。
- 调用 async1,依次打印”async1 start”、”async2”,将 await 后面的回调函数放到异步微任务队列。
- 执行 new Promise,输出”promise1”,将 then 里面的回调函数放入异步微任务队列。
- 执行耗时长的循环语句并打印 arr,并且输出”end”,这时候主栈执行完毕为空。
- 将异步微任务队列里的函数按照”先进先出”的顺序依次执行,输出”async1 end”,”promise2”。
- 将异步宏任务队列里的函数按照”先进先出”的顺序依次执行,输出”setTimeOut”。
1 | setTimeout(function(){ |
答案:
1 | "2" |
分析:
- 首先浏览器执行Js代码由上至下顺序,遇到 setTimeout,把 setTimeout 分发到宏任务 Event Queue 中
- new Promise 属于主线程任务直接执行打印 2
- Promis 下的 then 方法属于微任务,把 then 分到微任务 Event Queue 中
- console.log(‘4’) 属于主线程任务,直接执行打印4
- 又遇到 new Promise 也是直接执行打印 5,Promise 下到 then 分发到微任务 Event Queue中
- 又遇到 setTimouse 也是直接分发到宏任务 Event Queue中,等待执行
- console.log(‘10’) 属于主线程任务直接执行
- 遇到 bar() 函数调用,执行构造函数内到代码,打印 8,在 bar 函数中调用 foo 函数,执行 foo 函数到中代码,打印 9
- 主线程中任务执行完后,就要执行分发到微任务 Event Queue 中代码,实行先进先出,所以依次打印 3,6
- 微任务 Event Queue 中代码执行完,就执行宏任务 Event Queue 中代码,也是先进先出,依次打印 1,7。
Promise 本身是同步的立即执行函数, 当在 executor 中执行 resolve 或者 reject 的时候, 此时是异步操作, 会先执行 then/catch 等,当主栈完成后,才会去调用 resolve/reject 中存放的方法执行,打印 p 的时候,是打印的返回结果,一个 Promise 实例。
1 | console.log('script start') |
async 函数返回一个 Promise 对象,当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再执行函数体内后面的语句。可以理解为,是让出了线程,跳出了 async 函数体。
1 | async function async1(){ |