事件循环中涉及到promise的执行顺序你真的了解吗

818 阅读2分钟

我们面试关于事件循环总能碰到各种刁钻的问题,但是只要掌握了其中的本质,一顿分析下来再刁钻的问题也会迎刃而解。下面就让我们来一起探索其中的原理吧~ 首先,来看一段代码

new Promise(resolve => {
    console.log(1);
    resolve(3);
}).then(num => {
    console.log(num)
});
console.log(2)

// 输出顺序为123

下面我们就来分析上面这段代码的执行顺序:
第一步:new Promise(()=>{}).then(() => {})其中.then之前的代码是同步执行任务,所以会先打印出1。
第二步:resolve(3)promise在resolve之后状态会从pengding变为fulfilled,之后Promise对象的then方法就会被调用,但是注意这里的方法是一个异步微任务。
第三步:console.log(2)是同步任务。
所以,最终输出顺序为123。

如果在promise里面再加一个promise:

new Promise(resolve => {
    console.log(1);
    // resolve(3);
    Promise.resolve().then(()=> console.log(4))
}).then(num => {
    console.log(num)
});
console.log(2)

// 输出顺序为124

没有resolve(),promise的状态一直是pending,并不会出发then()。

const promise = new Promise((resolve, reject) => {
    console.log(1)
    resolve()
    console.log(2)
})
promise.then(() => {
    console.log(4)
})
console.log(5)
// 输出顺序为1254
  • 我们知道,JavaScript是基于事件驱动单线程执行的,所有任务都需要排队,也就是说前一个任务结束,才会去执行下一个任务。而像settimeout、ajax等异步操作的回调,会进入”任务队列“中,而且只有主线程中没有执行任何同步代码的前提下,才会执行异步回调。
  • Promise新建后立即执行,也就是说,Promise构造函数里的代码是同步执行的。
  • then方法指向的回调将在当前脚本所有同步任务执行完后执行。
  • 其实,setTimeout有个最小执行时间(minimum delay of 4ms ),并不是0s执行的。
  • Macrotasks和Microtasks 都属于异步任务中的一种,常用api分类: macrotasks: setTimeout,setInterval,setImmediate, I/O, UI rendering microtasks:process.nextTick, Promise, MutationObserver
  • 一个事件循环中只有一个macrotask任务,可以有一个或多个microtask任务。 其实还有很多知识点没有提到,后续会持续更新此文章~