返回

Promise异步编程的深入剖析

前端

深入理解Promise

Promise是JavaScript中用于处理异步编程的强大工具。它允许您将异步操作包装成一个对象,并提供一系列方法来处理其结果。

Promise有三种状态:

  • Pending: 初始状态,表示异步操作尚未完成。
  • Fulfilled: 成功状态,表示异步操作已成功完成。
  • Rejected: 失败状态,表示异步操作已失败。

您可以使用then()方法来处理Promise的结果。then()方法接受两个参数:一个成功回调函数和一个失败回调函数。当Promise的状态变为Fulfilled时,将调用成功回调函数;当Promise的状态变为Rejected时,将调用失败回调函数。

Promise与微任务

Promise与微任务之间存在着紧密的关系。微任务是JavaScript引擎在执行宏任务(如事件循环)之前执行的一组任务。微任务队列是存储微任务的地方,当微任务队列不为空时,JavaScript引擎会首先执行微任务队列中的所有任务,然后才会执行宏任务队列中的任务。

Promise的状态改变时,会将一个微任务添加到微任务队列中。这个微任务会执行Promise的回调函数,并将结果传递给下一个then()方法。

不同类型异步代码的执行顺序

Promise + 定时器

console.log('start');

setTimeout(() => {
  console.log('timer');
}, 0);

Promise.resolve().then(() => {
  console.log('promise');
});

console.log('end');

输出:

start
promise
end
timer

在这个示例中,console.log('start')首先执行,然后Promise被解析,并添加一个微任务到微任务队列。接下来,console.log('end')执行。由于微任务队列不为空,所以JavaScript引擎会在执行宏任务(定时器)之前执行微任务队列中的所有任务,因此console.log('promise')被执行。最后,定时器被执行,console.log('timer')被输出。

纯Promise

console.log('start');

Promise.resolve().then(() => {
  console.log('promise1');
});

Promise.resolve().then(() => {
  console.log('promise2');
});

console.log('end');

输出:

start
promise1
promise2
end

在这个示例中,console.log('start')首先执行,然后两个Promise被解析,并分别添加一个微任务到微任务队列。接下来,console.log('end')执行。由于微任务队列不为空,所以JavaScript引擎会在执行宏任务(定时器)之前执行微任务队列中的所有任务,因此console.log('promise1')console.log('promise2')被执行。

await + Promise

async function main() {
  console.log('start');

  await Promise.resolve();

  console.log('promise');

  console.log('end');
}

main();

输出:

start
promise
end

在这个示例中,console.log('start')首先执行,然后await Promise.resolve()暂停main()函数的执行,并添加一个微任务到微任务队列。接下来,console.log('end')执行。由于微任务队列不为空,所以JavaScript引擎会在执行宏任务(定时器)之前执行微任务队列中的所有任务,因此console.log('promise')被执行。最后,main()函数恢复执行,并输出console.log('end')

nextTick + Promise (Node.js)

console.log('start');

process.nextTick(() => {
  console.log('nextTick');
});

Promise.resolve().then(() => {
  console.log('promise');
});

console.log('end');

输出:

start
nextTick
promise
end

在这个示例中,console.log('start')首先执行,然后process.nextTick()将一个回调函数添加到nextTick队列。接下来,console.log('end')执行。由于nextTick队列不为空,所以Node.js会在执行宏任务(定时器)之前执行nextTick队列中的所有任务,因此console.log('nextTick')被执行。最后,Promise被解析,并添加一个微任务到微任务队列。由于微任务队列不为空,所以JavaScript引擎会在执行宏任务(定时器)之前执行微任务队列中的所有任务,因此console.log('promise')被执行。

结论

通过对Promise与微任务关系的深入理解,我们可以更加轻松地编写出简洁、易于维护的异步代码。Promise可以帮助我们避免回调地狱,并使代码更具可读性。