|
promise 的处理程序 .then、.catch 和 .finally 都是异步的。
即便一个 promise 立即被 resolve,.then、.catch 和 .finally 下面 的代码也会在这些处理程序之前被执行。
示例代码如下:
let promise = Promise.resolve();
promise.then(() => alert("promise done!"));
alert("code finished"); // 这个 alert 先显示
如果你运行它,你会首先看到 code finished,然后才是 promise done。
这很奇怪,因为这个 promise 肯定是一开始就完成的。
为什么 .then 会在之后才被触发?这是怎么回事?
微任务队列(Microtask queue)
异步任务需要适当的管理。为此,ECMA 标准规定了一个内部队列 PromiseJobs,通常被称为“微任务队列(microtask queue)”(V8 术语)。
如 规范 中所述:
队列(queue)是先进先出的:首先进入队列的任务会首先运行。
只有在 JavaScript 引擎中没有其它任务在运行时,才开始执行任务队列中的任务。
或者,简单地说,当一个 promise 准备就绪时,它的 .then/catch/finally 处理程序就会被放入队列中:但是它们不会立即被执行。当 JavaScript 引擎执行完当前的代码,它会从队列中获取任务并执行它。
这就是为什么在上面那个示例中 “code finished” 会先显示。
promise 的处理程序总是会经过这个内部队列。
如果有一个包含多个 .then/catch/finally 的链,那么它们中的每一个都是异步执行的。也就是说,它会首先进入队列,然后在当前代码执行完成并且先前排队的处理程序都完成时才会被执行。
如果执行顺序对我们很重要该怎么办?我们怎么才能让 code finished 在 promise done 之后出现呢?
很简单,只需要像下面这样使用 .then 将其放入队列:
Promise.resolve()
.then(() => alert("promise done!"))
.then(() => alert("code finished"));
现在代码就是按照预期执行的。
|
|