.then()方法返回的promise对象的目的是什么?

时间:2017-07-13 00:10:33

标签: javascript asynchronous promise es6-promise

我在多个网站上看到,promise.prototype中的.then()方法返回一个promise。不幸的是,没有消息来源描述其背后的原因。

  

then()方法返回一个Promise。它最多需要两个参数:Promise的成功和失败案例的回调函数。 - developer.mozilla.com

为什么/何时需要此返回的promise对象,此promise对象与原始对象的关系如何。

非常感谢你的帮助。

3 个答案:

答案 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);
});

这是一步一步发生的事情:

  1. a(100)被调用。这会调用delay(设置一个计时器)并返回一个我将调用a1_promise的承诺,仅仅是为了描述这里的内容。

  2. 然后,因为我们正在执行a(100).then(b),我们会从a(100)获取返回值a1_promise并调用a1_promise.then(b)。这将b函数存储为.then()处理函数,以便在将来解析a1_promise时调用(不是现在)。然后返回一个新的承诺,我将称之为a2_promise

  3. 然后,因为我们正在执行a(100).then(b).then(c),我们会从a(100).then(b)获取返回值a2_promise并调用a2_promise.then(c)。这将c函数存储为.then()处理函数,以便在将来解析a2_promise时调用(不是现在)。然后返回一个新的承诺,我将称之为a3_promise

  4. 然后,因为我们正在执行a(100).then(b).then(c).then(...),我们会从a(100).then(b),then(c)获取返回值a3_promise并调用a3_promise.then(c)。这将我们的最后一个匿名函数存储为.then()处理函数,以便在将来a3_promise解析时调用(不是现在)。然后返回一个新的承诺,我将其称为a4_promise(没有人使用)。

  5. 现在我们已完成同步执行。请注意,a().then(b).then(c).then(...)全部是同步执行的。已经在所有不同的承诺上调用了所有三种.then()方法。但是,由于此处创建的任何承诺尚未解决,因此.then()处理程序中没有一个实际上已被调用。当承诺得到解决时,它们都被存储起来以备将来调用。

  6. 现在有一段时间过去了,a()内创建的计时器会触发并解析a1_promise。然后,会触发a1_promise调用它拥有的任何.then()处理程序,并将a1_promise的已解析值传递给100 + 1101.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`已解决。

  7. 现在又过了一些时间,在b1_promise内创建的计时器会触发101 + 10并使用111的新修改值a2_promise来解析a2_promise。这告诉.then()它现在可以使用该值解析。

  8. 然后c(111)可以调用它的c_promise处理程序,并且可以执行c_promise,这又像步骤6中那样返回111 * 100 which is尚未解决。

  9. 一段时间过后,. That tells the结算的值为.then() 11,100 console.log() a3_promise`,现在可以使用该值解析。

  10. a3_promise可以调用它的11000处理程序,这是我们在链末尾的箭头函数,我们得到{{1}}显示{{1}}作为最终价值。

答案 2 :(得分:0)

这是Promisse的好地方。

例如,您可以将许多方法链接到上面的方法结果(在本例中为Promisse.resolve)。像this

一样