.then() 返回一个承诺的事实有三个主要方面。
第一个是您可以像这样链接操作:
a().then(b).then(c).then(d)
因为.then() 返回一个新的promise,所以在新的promise 解决之前,下面的.then() 处理程序不会被执行。如果 b 和 c 是同步的,那么新的 Promise 将在它们返回时解析,并且当第一个 b 完成时链将继续,然后当 c 完成时。
第二个是新的承诺会受到.then()处理程序返回的影响。这允许 b、c 和 d 是异步操作,它们本身返回 Promise,并且链将被适当地排序。所以,想象一下 b 和 c 都自己返回 Promise。
首先你得到a() 返回一个承诺。当它解决时,它的.then() 处理程序被调用。然后将运行b。如果b() 也是一个异步操作并且它返回一个新的promise,那么a.then(b) 返回的所有其他.then() 处理程序链接到的promise 将不会被解析,直到b 返回的新promise 被解析。这允许.then() 处理程序将新的异步项插入到链中。这是链接承诺的一个非常重要的方面。 .then() 处理程序可以将它们自己的异步操作插入到链中,甚至可以根据先前的结果或当前状态有条件地执行此操作。
如果a().then(b) 刚刚返回了与a() 返回的相同的承诺,那么所有后续的.then() 处理程序将无法“等待”b() 返回的承诺,因为它们将被链接到a() 承诺,它已经解决了。正是这个新 Promise 的返回允许 .then() 处理程序中的函数影响后续链,因为新的 Promise 受 .then() 处理程序返回的内容影响。
第三个方面是.then() 处理程序的返回值可以影响新承诺的解析值,这就是传递给链中下一个.then() 处理程序的值。如果a().then(b) 刚刚返回了与a() 返回的相同的承诺,那么所有后续的.then() 处理程序只会看到来自a() 的相同解析值,因为该解析值已经在a() 解析时设置,它在@ 之前987654350@ 调用了它的.then() 处理程序。这些后续的.then() 处理程序将无法从.then() 处理程序内的代码继承新的解析值。
让我们看一个具体的场景。我将使用延迟方法作为一个简单的函数示例,该函数返回一个将来会解析的 Promise。
function delay(t, val) {
return new Promise(resolve => {
setTimeout(() => resolve(val), t);
});
}
然后,定义几个不同的异步函数:
function a(val) {
return delay(100, val + 1);
}
function b(val) {
return delay(50, val + 10);
}
function c(val) {
return val * 100;
}
现在,将它们全部串起来:
a(100).then(b).then(c).then(val => {
console.log("all done: ", val);
});
这是一步一步发生的:
a(100) 被调用。这会调用delay(它设置一个计时器)并返回一个我将调用a1_promise 的promise,只是为了在此处进行描述。
然后,因为我们在做a(100).then(b),所以我们从a(100)(即a1_promise)获取返回值并调用a1_promise.then(b)。这会将b 函数存储为.then() 处理函数,以便在将来某个时间解决a1_promise 时调用(不是现在)。然后返回一个新的承诺,我将称之为a2_promise。
然后,因为我们正在执行a(100).then(b).then(c),所以我们从a(100).then(b)(即a2_promise)获取返回值并调用a2_promise.then(c)。它将c 函数存储为.then() 处理函数,以便在将来某个时间解决a2_promise 时调用(不是现在)。然后返回一个新的承诺,我将称之为a3_promise。
然后,因为我们在做a(100).then(b).then(c).then(...),所以我们从a(100).then(b),then(c)(即a3_promise)获取返回值并调用a3_promise.then(c)。它将我们最后一个匿名函数存储为 .then() 处理函数,以便在将来某个时间解决 a3_promise 时调用(不是现在)。然后返回一个新的承诺,我将称之为a4_promise(没有人使用)。
现在我们完成了同步执行。请注意,a().then(b).then(c).then(...) 都是同步执行的。所有三个.then() 方法都已经在所有不同的promise 上调用过。但是,由于此处创建的所有承诺都尚未解决,因此实际上还没有调用任何 .then() 处理程序。它们都刚刚被存储起来,以便将来在 promise 解决时调用。
现在经过一段时间,a() 内部创建的计时器触发并解析a1_promise。然后触发a1_promise 调用它拥有的任何.then() 处理程序并将a1_promise 的解析值传递给它,在这种情况下将是100 + 1 或101。由于a1_promise 上只有一个.then() 处理程序并且它是b() 函数,因此它现在将调用b(101)。执行它只会返回一个新的承诺,b() 创建并返回。我们将把这个新的承诺称为b_promise。在a1_promise() 内部,它知道它在之前调用a1_promise.then() 时创建了a2_promise(),因此它知道当它执行存储的.then() 处理程序以及.then() 处理程序执行并返回一个新的promise 时,它持有关闭解决 a2_promise that it created until thatb_promiseis resolved. In this way, you can see that further execution of the chain is now controlled by theb_promise, thus the code executing inb()and the promise is returned are inserted into thea().then().then().then()chain holding off future.then()handlers until theb_promise` 已解决.
现在又过了一段时间,在 b() 内部创建的计时器触发并使用新修改的 101 + 10 值解析 b1_promise,即 111。这告诉a2_promise,它现在可以使用该值进行解析。
然后a2_promise 可以调用它的.then() 处理程序并可以执行c(111),就像在步骤6 中返回的c_promise 一样,它还没有解决。
一段时间过去了,c_promise 解析为 111 * 100 which is11,100. That tells thea3_promise`,现在它可以使用该值解析。
然后 a3_promise 可以调用它的 .then() 处理程序,这是我们在链末尾的箭头函数,我们得到一个 console.log() 显示 11000 作为最终值。