事件循环

JavaScript是单线程

学习及参考网址

阮一峰 JavaScript 运行机制详解:再谈Event Loop

MDN 并发模型与事件循环

JavaScript语言的一大特点就是单线程,同一时间只能做一件事情。

任务队列

单线程就意味着,代码是从上向下执行的,所有任务需要进行排队,前一个任务结束的时候,下一个任务才会进行执行。

因此这些任务被分为了两种:

  • 同步任务
  • 异步任务

同步指:在主线程上进行排队的任务,只有前一个任务执行完毕,才会执行后一个任务

异步指:不进入主线程,而进入任务队列的任务,只有“任务队列”通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

一般情况下,任务执行可以分为三个队列

主线程 微任务 宏任务
console.log() Promise.then setTimeout
接口调用

一般情况下执行顺序为:主线程 > 微任务 > 宏任务

可以用几个题来将事件循环弄明白,上题!

setTimeout(function () {
  console.log('setTimeout1')
  new Promise(function (resolve) {
    resolve()
  }).then(function () {
    new Promise(function (resolve) {
      resolve()
    }).then(function () {
      console.log('then4')
    })
    console.log('then2')
  })
})

new Promise(function (resolve) {
  console.log('promise1')
  resolve()
}).then(function () {
  console.log('then1')
})

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

console.log(2)

queueMicrotask(() => {
  console.log('queueMicrotask1')
})

new Promise(function (resolve) {
  resolve()
}).then(function () {
  console.log('then3')
})

// promise1
// 2
// then1
// queueMicrotask1
// then3
// setTimeout1
// then2
// then4
// setTimeout2

代码执行时,由上向下依次执行,setTimeout进入宏任务队列,接着向下执行到Promise,之前我一度以为只要进入到Promise的调用时就进入了异步队列中,其实这个想法是错误的,Promise只有进入.then的时候才是进入了微任务队列,因此promise1直接输出,遇到Promise.then,进入微任务队列中进行等待,后面setTimeout再次进入宏任务队列,输出2,queueMicrotask也是微任务队列,因此进入微任务队列中,再次遇到Promise.then,进入微任务队列。因此执行顺序为目前表格所示。

主线程 微任务 宏任务
promise1 then1 setTimeout1及之后代码
2 queueMicrotask1 setTimeout2
then3

事件循环是JavaScript中必须学习的一部分,通过代码题将自己的基础再进行巩固。