【问题标题】:How do I chain multiple conditional promises?如何链接多个条件承诺?
【发布时间】:2016-11-25 11:47:43
【问题描述】:

在我的代码中,我有条件任务,它们都返回一个承诺。我需要按顺序运行任务。

我当前的实现如下所示:

var chain = [];

if (/* some condition for task A */) {
    chain.push(function(doContinue){
        taskA().then(doContinue);
    });
}

if (/* some condition for task B */) {
    chain.push(function(doContinue){
        taskB().then(doContinue);
    });
}

if (/* some condition for task C */) {
    chain.push(function(doContinue){
        taskC().then(doContinue);
    });
}

var processChain = function () {
    if (chain.length) {
        chain.shift()(processChain);
    } else {
        console.log("all tasks done");
    }
};

processChain();

这很好用,但最初我正在寻找一种方法来创建仅使用 Promises 的链并使用 .then 链接所有函数,但我无法获得可行的解决方案。

如果有一种更简洁的方法,只使用 Promise 和 then 调用链,那么我很乐意看到一个例子。

【问题讨论】:

  • 您需要异步评估条件(即在上一个承诺步骤之后)还是同步评估?
  • @Bergi 条件可以在开始时评估,不依赖promise生成的结果。
  • 那么raina77ows 解决方案非常适合您。

标签: javascript promise


【解决方案1】:

一种可能的方法:

var promiseChain = Promise.resolve();
if (shouldAddA) promiseChain = promiseChain.then(taskA);
if (shouldAddB) promiseChain = promiseChain.then(taskB);
if (shouldAddC) promiseChain = promiseChain.then(taskC);
return promiseChain;

另一个:

return Promise.resolve()
  .then(shouldAddA && taskA)
  .then(shouldAddB && taskB)
  .then(shouldAddC && taskC);

【讨论】:

  • 需要指出的是,这两种方式并不完全等价。在方法 1 中,每个 .then() 要么被链接,要么被链接。在方法 2 中,每个.then() 都是无条件链接的,并且有或没有成功处理程序。每个链接的.then(),即使没有处理程序,也会引入下游延迟,因此与方法 1 相比,方法 2 将为每个失败的测试引入额外的下游延迟。
  • 在许多情况下,也许是大多数情况下,差异并不重要。延迟的数量级(在 Opera 41.0 下使用 jsFiddle 中的本机 Promises 的 1.4 GHz 上网本上)约为每 10000 .then(null) 1 秒。最有可能出现差异的情况是其他一些承诺与构建的链竞争;与方法 1 相比,方法 2 输掉比赛的机会更大。
  • 你是上帝!真的行!而且很干净! :D 为什么返回的 promiseChain 没有被调用?它实际上是如何启动的?
  • 因为承诺永远不会被“调用”。人们需要创建一系列行动并对解决方案做出反应——无论成功与否。 promiseChain 存储了一个封装这个链的对象。
  • @raina77ow 感谢您的解释。我不完全同意您不“调用”承诺,因为某些事情必须首先触发此事件链的执行(并且它显然是在说明封装对象的名称),否则它会在您每次添加新动作时执行,但我明白你的意思。无论如何,您的解决方案很棒,非常感谢! :)
【解决方案2】:

您可以使用新的async/await 语法

async function foo () {
  let a = await taskA()
  if (a > 5) return a // some condition, value

  let b = await taskB()
  if (b === 0) return [a,b] // some condition, value

  let c = await taskC()
  if (c < 0) return "c is negative" // some condition, value

  return "otherwise this"
}

foo().then(result => console.log(result))

这样做的好处是 - 除了代码非常扁平和可读 (imo) - 值 abc 在同一范围内都可用。这意味着您的条件和返回值可以取决于您的任务承诺值的任意组合。

【讨论】:

  • 您的示例虽然很有帮助,但与原始问题的情况有些不同。问题是如何对异步操作进行条件化(或跳过),但您的操作将始终按从上到下的顺序运行,对第二个或第三个操作进行条件化。
  • @BeniRose 我不确定你的意思——例如,当a &gt; 5taskBtaskC 都不会被执行时——那些异步操作将被有效地跳过 – 基于条件。如果taskA 是由一些外部条件控制的,那也没关系。这个答案演示了async/await 本质上允许您模糊同步和异步代码之间的界限。
  • 即,当您了解async/await 的工作原理时,“链接多个条件承诺” 的问题就消失了——提问者的头脑中没有像 这样的术语“链”甚至“承诺”;问题变成了“如何对多个条件进行排序?”;答案很简单:if .../else if .../else ...
  • async/await 展示了语言关键字如何将Promise 之类的抽象提升到一个新的水平。程序员不关心“resolving”“rejecting”.then.catch;可以忘记整个 Promise API。程序员可以用高级关键字围绕涉及异步的函数和函数调用编写普通程序。缺少这个关键的区别是用盲目的眼光看待抽象的力量。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-01
  • 1970-01-01
  • 2018-02-25
  • 1970-01-01
  • 2021-08-01
  • 2019-05-24
  • 2020-03-19
相关资源
最近更新 更多