面试题——事件循环eventloop

72 阅读2分钟

首先要清楚一个概念,JS是单线程的,单线程意味着同一个时间只能做一件事情。 但是会出现一种情况,有些任务是耗时的,会阻塞代码的执行。 我们可以把代码分为同步代码异步代码

同步代码:
console.log(1)
console.log(2)

异步代码:

setTimeout(()=>{
   console.log(1)
},100)

还包括setInterval,Ajax/Fetch,事件绑定等。 这些异步任务都是费时的。

同步代码:立即放入JS引擎(JS主线程)执行,并原地等待结构 异步代码:先放入宿主环境(浏览器/Node),不必原地等待结果,不会阻塞主线程继续往下执行,异步结果在将来执行。

代码的执行过程:

  1. 执行栈先去执行同步代码。
  2. 异步代码放到宿主环境中执行,等到时间执行回调函数,将回调函数push到任务队列中。
  3. 等到执行栈中的同步任务全都执行完毕回到任务队列中查看是否有异步任务,若有再把异步任务push到执行栈中进行执行。
console.log(1)
setTimeout(function(){
  console.log(2)
},2000)
console.log(3)

执行结果:1 3 2 以上的整个过程就是事件循环。

JS把异步任务分为宏任务微任务

  • 宏任务包括:script全文,setTimeout,setInterval等。
  • 微任务包括:Promise,nextTick等。 注意:promise本身是同步的,promise.then()/.catch()是异步的

那么此时代码执行过程可以分为三种代码:同步代码微任务的异步代码宏任务的异步代码

执行顺序为:

  1. 同步代码。
  2. 微任务的异步代码。
  3. 宏任务的异步代码。
console.log(1)
setTimeout(function(){
   console.log(2)
})
const p = new Promise((resolve,reject) =>{
   console.log(3)
   resolve(1000)
   console.log(4)
})
p.then(data=>{
   console.log(data)
})
console.log(5)

执行结果:1 3 4 5 1000 2

首先去执行同步代码打印1,setTimeout属于宏任务后执行,执行promise本身(同步代码),打印3,4,打印5,此时同步代码执行结束。然后回到微任务队列打印标记的1000,此时微任务执行结束。然后再到宏队列中执行剩余的宏任务打印2。