浅谈Event loop

JS的运行机制

  JS是单线程的,但鉴于浏览器中有很多事件都是异步的,所以浏览器会开启多个线程去执行任务。

 执行栈与任务队列

  执行栈是JS脚本在运行过程中线程执行代码的顺序。一般最先开始压入执行栈的是main函数,根据先进后出的原则,只有等函数完全执行结束才会从栈中弹出,而任务队列是因为在栈执行的过程中会出现异步函数,这时候就需要把该函数丢给WebAPIs,等WebAPIs执行完后会放入任务队列中,当栈为空时会把回调函数压入栈中执行。要注意的是,任务队列中只会存在异步函数。

 

 

 什么是宏任务与微任务

 

  宏任务(macrotask)是一个event loop有一个或者多个task队列,常见的task的任务源有:

  • setTimeout
  • setInterval
  • setImmediate
  • I/O
  • UI rendering

   微任务(microtask) 队列和task 队列有些相似,都是先进先出的队列,由指定的任务源去提供任务,不同的是一个 event loop里只有一个microtask 队列,同一个执行环境下为人物要先于红任务执行,只有微任务队列执行为空时才会执行宏任务队列。

一个例子:

Promise.resolve().then(function promise1 () {
       console.log('promise1');
    })
setTimeout(function setTimeout1 (){
    console.log('setTimeout1')
    Promise.resolve().then(function  promise2 () {
       console.log('promise2');
    })
}, 0)

setTimeout(function setTimeout2 (){
   console.log('setTimeout2')
}, 0)

 

 

 

运行过程:

script里的代码被列为一个task,放入task队列。

循环1:

  • 【task队列:script ;microtask队列:】
  1. 从task队列中取出script任务,推入栈中执行。
  2. promise1列为microtask,setTimeout1列为task,setTimeout2列为task。
  • 【task队列:setTimeout1 setTimeout2;microtask队列:promise1】
  1. script任务执行完毕,执行microtask checkpoint,取出microtask队列的promise1执行。

循环2:

*【task队列:setTimeout1 setTimeout2;microtask队列:】 4. 从task队列中取出setTimeout1,推入栈中执行,将promise2列为microtask。

  • 【task队列:setTimeout2;microtask队列:promise2】
  1. 执行microtask checkpoint,取出microtask队列的promise2执行。

循环3:

  • 【task队列:setTimeout2;microtask队列:】
  1. 从task队列中取出setTimeout2,推入栈中执行。 7.setTimeout2任务执行完毕,执行microtask checkpoint。
  • 【task队列:;microtask队列:】

拓展demo: 

console.log('script start')

async function async1() {
  await async2()
  console.log('async1 end')
}
async function async2() {
  console.log('async2 end')
}
async1()

setTimeout(function() {
  console.log('setTimeout')
}, 0)

new Promise(resolve => {
  console.log('Promise')
  resolve()
})
  .then(function() {
    console.log('promise1')
  })
  .then(function() {
    console.log('promise2')
  })

console.log('script end')

 

 

posted @ 2021-05-12 10:36  发条鸭  阅读(67)  评论(0)    收藏  举报