彻底搞懂事件循环

Event Loop 即事件循环,是指浏览器或Node的一种解决 JavaScript 单线程运行时不会阻塞的一种机制,也就是我们经常使用异步的原理。

JS 在执行的过程中会产生执行环境,这些执行环境会被顺序的加入到执行栈中。如果遇到异步的代码,会被挂起并加入到 Task(有多种 task) 队列中。一旦执行栈为空,Event Loop 就会从 Task 队列中拿出需要执行的代码并放入执行栈中执行,所以本质上来说 JS 中的异步还是同步行为。

不同的任务源会被分配到不同的 Task 队列中,任务源可以分为宏任务(macrotask) 微任务(microtask)

宏任务 MacroTask 包括:

  • script (整体代码)
  • setTimeout
  • setInterval
  • setImmediate
  • I/O
  • UI render

微任务 MicroTask 包括:

  • process.nextTick (Node 独有)
  • Promise then
  • async/await (实际就是 promise)
  • MutationObserver (html5 新特性)

#浏览器

Javascript 有一个main thread 主线程和call-stack 调用栈(执行栈),所有的任务都会被放到调用栈等待主线程执行。

JS 调用栈

JS 调用栈采用的是后进先出的规则,当函数执行的时候,会被添加到栈的顶部,当执行栈执行完成后,就会从栈顶移出,直到栈内被清空。

同步任务和异步任务

Javascript 单线程任务被分为同步任务和异步任务,同步任务会在调用栈中按照顺序等待主线程依次执行,异步任务会在异步任务有了结果后,将注册的回调函数放入任务队列中等待主线程空闲的时候(调用栈被清空),被读取到栈内等待主线程的执行。

在浏览器中,一次 Event Loop 顺序是这样的:

  1. 执行同步代码,这属于宏任务
  2. 执行栈为空,查询是否有微任务需要执行
  3. 执行所有微任务
  4. 必要的话渲染 UI
  5. 然后开始下一轮 Event Loop,执行宏任务中的异步代码

其中,需要注意 async/await 的理解。async/await 在底层转换成了 promise 和 then 回调函数。每次我们使用 await,解释器都创建一个 Promise 对象,然后把剩下的 async 函数中的操作放到 then 回调函数中。

setTimeout(function () {
    console.log(1);
});

new Promise(function(resolve,reject){
    console.log(2)
    resolve(3)
}).then(function(val){
    console.log(val);
})
//结果为2 3 1 

你可能感兴趣的:(vue.js,前端,javascript)