# JS中的EventLoop

# 浏览器中的EventLoop

  1. JS是单线程的,比如在操作Dom的时候,不能删除一个Dom节点的同时再去操作同一个Dom节点。或者在进行一个网络请求的时候,我们往往需要等待这个请求完成之后才能对请求回来的数据进行Dom的渲染。
    那浏览器到底是如何协调这些事件、交互的呢?这个时候就要用到EventLoop-事件循环机制了。

  2. 任务队列

  • JS中有个任务队列的概念
  • JS中将任务主要分为宏任务(macrotask)和微任务(microtask)
    • 宏任务(macrotask): script脚本,request回调,event事件回调,setTimeour, setInterval, setImmediate(node环境)、I/O、UI rendering
    • 微任务(microtask): Promise,process.nextTick(node)
  1. 执行步骤
  • 同一个上下文中,执行顺序是同步代码 -> 微任务 -> 宏任务

# 代码解析

console.log("start")
setTimeout(()=>{
    console.log("timer1")
    new Promise(function(resolve){
     console.log("promise start")
      resolve();
}).then(function() {
        console.log("promise1")
    })
}, 0)

setTimeout(()=>{
    console.log("timer2")
    Promise.resolve().then(function() {
        console.log("promise2")
    })
}, 0)
console.log("end")

// 浏览器输出
// start
// end
// timer1
// promise start
// promise1
// timer2
// promise2

结果分析:
在同一个上下文中,从上到下依次执行,首先遇到console.log("start")同步代码,先执行同步代码,所以第一个输出start,向下遇到第一个setTimeout为宏任务,塞进宏任务队列,第二个setTimeout同理,最后又遇到console.log("end")同步代码,执行并输入end
同步任务完成后,JS执行栈为空,检查微任务也为空,检查宏任务中存在需要执行的任务,所以按先进先出的规则执行宏任务队列,首先执行第一个setTimeout,进来首先是console.log("timer1")同步代码,所以执行并输入timer1,然后执行new Promise, new Promise中首先是console.log("promise start"),输出promise start,接着执行了resolve, Promise.then同样属于微任务,塞入微任务中挂起。这一轮宏任务执行完成,检查微任务,存在Promise.then,执行并输出promise1。 执行完成后,JS执行栈为空,继续查找宏任务,执行第二个setTimeout,输出timer2,遇到Promise.resolve.then微任务,塞入微任务挂起,setTimeout执行完成,检查微任务,执行输出promise2

# async/await

async/await 是ES7中推出的语法糖,是针对ES6generate/yield的语法糖,async返回的同样是一个Promise对象,遇到await就会等待异步操作完成,再继续执行后面的语句。注意:await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try...catch代码块中。

Last Updated: 4/26/2021, 6:07:35 PM