setTimeout、Promise、Async/Await 有什么区别?

2,675 阅读2分钟
  • 浏览器内核是多线程,JavaScript是单线程语言,其他所谓的“多线程”都是模拟出来的。
  • Event Loop是JavaScript的执行机制
// 今日头条面试题
async function async1() {
    console.log('async1 start')
    await async2()
    console.log('async1 end')
}
async function async2() {
    console.log('async2')
}
console.log('script start')
setTimeout(function () {
    console.log('settimeout')
})
async1()
new Promise(function (resolve) {
    console.log('promise1')
    resolve()
}).then(function () {
    console.log('promise2')
})
console.log('script end')

题目的本质,就是考察setTimeoutpromiseasync await的实现及执行顺序,以及JS的事件循环的相关问题。

答案:

script start
async1 start
async2
promise1
script end
async1 end
promise2
settimeout

这里涉及到MicrotasksMacrotasksEvent Loop以及 JS 的异步运行机制。

Event Loop

JS主线程不断的循环往复的从任务队列中读取任务,执行任务,其中运行机制称为事件循环。

microtasks(微任务)、macrotasks(宏任务)

微任务和宏任务皆为异步任务,它们都属于一个队列,主要区别在于他们的执行顺序,Event Loop的走向和取值。

宏任务

#浏览器Node
I/O
setTimeout
setInterval
setImmediate
requestAnimationFrame

微任务

#浏览器Node
process.nextTick
MutationObserver
Promise.then catch finally
  • 浏览器的Event loop是遵循的HTML5的标准
  1. 先取出一个macrotask来执行,执行完成后下一步
  2. 取一个microtask来执行,执行完成后,再取出一个来执行,直到microtask queqe清空,执行下一步
  3. 更新UI渲染
  • NodeJs的Event loop遵循的是libuv
  1. 初始化Event loop
  2. 执行主代码,同样遇到异步操作,分配给对应的队列,直到主代码执行完成
  3. 执行代码中出现的所有microtask 先执行完所有的NextTick,再执行其他micro task,
  4. 开始Event loop

总结:

  1. 在执行上下文栈的同步任务执行完后;
  2. 首先执行Microtask队列,按照队列先进先出的原则,一次执行完所有Microtask队列任务;
  3. 然后执行Macrotask/Task队列,一次执行一个,一个执行完后,检测 Microtask是否为空;
  4. 为空则执行下一个Macrotask/Task;
  5. 不为空则执行Microtask

内容搜集自网络