我在多个网站上看到,promise.prototype中的.then()方法返回一个promise。不幸的是,没有消息来源描述其背后的原因。
then()方法返回一个Promise。它最多需要两个参数:Promise的成功和失败案例的回调函数。 - developer.mozilla.com
为什么/何时需要此返回的promise对象,此promise对象与原始对象的关系如何。
非常感谢你的帮助。
答案 0 :(得分:5)
承诺是异步执行的,你永远不知道什么时候执行then()。
承诺可以返回一个承诺,这允许您在单行代码中链接异步事件处理。
Mozilla给出的示例代码:
doSomething().then(function(result) {
return doSomethingElse(result);
})
.then(function(newResult) {
return doThirdThing(newResult);
})
.then(function(finalResult) {
console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);
它避免了“厄运金字塔”:
doSomething(function(result) {
doSomethingElse(result, function(newResult) {
doThirdThing(newResult, function(finalResult) {
console.log('Got the final result: ' + finalResult);
}, failureCallback);
}, failureCallback);
}, failureCallback);
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises
答案 1 :(得分:1)
.then()
返回承诺的事实有三个主要方面。
第一个是你可以链接这样的操作:
a().then(b).then(c).then(d)
因为.then()
返回一个新的promise,所以在新的promise解析之前,不会执行以下.then()
个处理程序。如果b和c是同步的,那么新的承诺将在他们返回时解决,并且链将在第一次b
完成后继续,然后在c
完成时继续。
第二个是新承诺可能受.then()
处理程序返回的影响。这允许b,c和d是异步操作,它们本身返回promise并且链将被适当地排序。所以,想象一下b和c都会自己返回承诺。
首先,你得到a()
一个承诺。当结算解析时,会调用其.then()
处理程序。那将运行b
。如果b()
也是异步操作并且它返回一个新的promise,那么a.then(b)
返回所有其他.then()
处理程序所链接的承诺将不会得到解决,直到新的承诺为止。 b返回已解决。这允许.then()
处理程序将新的异步项插入到链中。这是链接承诺的一个非常重要的方面。 .then()
处理程序可以将它们自己的异步操作插入到链中,它们甚至可以根据先前的结果或当前状态有条件地执行它。
如果a().then(b)
刚刚返回a()
返回的相同承诺,那么所有后续.then()
处理程序将无法等待"对于b()
返回的承诺,因为它们已经与a()
承诺链接,并且已经解决了。正是这个新promise的返回允许.then()
处理程序中的函数影响后续链,因为新的promise会受.then()
处理程序返回的影响。
第三个方面是.then()
处理程序的返回值可以影响新promise的已解析值,这是传递给下一个.then()
处理程序的值在链中。如果a().then(b)
刚刚返回a()
返回的相同承诺,则所有后续.then()
处理程序只会看到来自a()
的相同解析值,因为已解决的值已在a()
解析了a().then()
调用其.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
的承诺,仅仅是为了描述这里的内容。
然后,因为我们正在执行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()
方法。但是,由于此处创建的任何承诺尚未解决,因此.then()
处理程序中没有一个实际上已被调用。当承诺得到解决时,它们都被存储起来以备将来调用。
现在有一段时间过去了,a()
内创建的计时器会触发并解析a1_promise
。然后,会触发a1_promise
调用它拥有的任何.then()
处理程序,并将a1_promise
的已解析值传递给100 + 1
,101
或.then()
。由于a1_promise
上只有一个b()
处理程序且它是b(101)
函数,因此它现在将调用b()
。执行该操作只会返回b_promise
创建并返回的新承诺。我们将称之为新承诺a1_promise()
。在a2_promise()
内部,它知道它在a1_promise.then()
之前被调用时创建了.then()
,因此它知道它何时执行存储的.then()
处理程序和a2_promise that it created until that
处理程序执行并返回一个新的promise,然后它不再解析is resolved. In this way, you can see that further execution of the chain is now controlled by the
b_promise , thus the code executing in
b_promise and the promise is returned are inserted into the
b()chain holding off future
a()。then()。then() .then()handlers until the
。然后()b()
b_promise`已解决。
现在又过了一些时间,在b1_promise
内创建的计时器会触发101 + 10
并使用111
的新修改值a2_promise
来解析a2_promise
。这告诉.then()
它现在可以使用该值解析。
然后c(111)
可以调用它的c_promise
处理程序,并且可以执行c_promise
,这又像步骤6中那样返回111 * 100 which is
尚未解决。
一段时间过后,. That tells the
结算的值为.then()
11,100 console.log()
a3_promise`,现在可以使用该值解析。
a3_promise可以调用它的11000
处理程序,这是我们在链末尾的箭头函数,我们得到{{1}}显示{{1}}作为最终价值。
答案 2 :(得分:0)
这是Promisse的好地方。
例如,您可以将许多方法链接到上面的方法结果(在本例中为Promisse.resolve)。像this
一样