logan70 / Blog

写博客的地方,觉得有用的给个Star支持一下~
81 stars 9 forks source link

执行机制 - 宏任务和微任务分别有哪些 #34

Open logan70 opened 4 years ago

logan70 commented 4 years ago

宏任务和微任务分别有哪些

为何区分宏任务和微任务

确保一致的执行顺序

假设有以下代码,对请求结果作缓存:

let data
function getData() {
  if (data) {
    console.log('loaded data')
  } else {
    ajax().then(data => {
      console.log('loaded data')
    })
  }
}

这样实现带来的问题是在有缓存和无缓存的情况下,执行顺序会出现不一致的情况:

console.log('get data start')
getData()
console.log('get data end')

上方代码在无缓存时调用,打印顺序为get data start -> get data end -> loaded data

有缓存时调用,打印顺序为get data start -> loaded data -> get data end

如果这些打印操作变为数据修改操作,就可能导致意料之外的情况发生,所以我们可以使用微任务来确保一致的执行顺序:

function getData() {
  if (data) {
    window.queueMicrotask(() => {
      console.log('loaded data')
    })
  } else {
    ajax().then(data => {
      console.log('loaded data')
    })
  }
}

这样无论有无缓存,打印顺序都为get data start -> get data end -> loaded data

批量操作

将批量操作统一处理,避免多次调用的开销。

下面的代码片段演示了如何对多个消息进行处理:通过一个微任务在当前宏任务退出时将这些消息作为单一的对象发送出去。

const messageQueue = []

let sendMessage = message => {
  messageQueue.push(message)

  if (messageQueue.length === 1) {
    queueMicrotask(() => {
      const json = JSON.stringify(messageQueue)
      messageQueue.length = 0
      fetch('url-of-receiver', json)
    })
  }
}

时效性

上面提到的两个场景大家可能认为可以使用setTimeout替代,但有一个容易忽略的点是,假设上述任务执行时,任务队列中有宏任务等待执行,且宏任务改变了数据或阻塞线程时间过长,此时若使用setTimeout实现,可能会和预期表现有出入。

所以在有数据时效性要求的场景下,使用微任务可以确保当前任务执行完后执行,例如实时数据分析等。

宏任务有哪些

微任务有哪些