如何提前退出一个由承诺组成的组合

How to early exit a composition of Promises

本文关键字:承诺 组合 一个 退出 何提前      更新时间:2023-09-26

我想这样做:

return1stPromise()
  .then(if1stPromiseSucceeds) // returns 2nd Promise
  .catch(if1stPromiseFails)
  .then(if2ndPromiseSucceeds) // execute only if 1st Promise succeeds

我希望只有在第一个承诺成功时才执行第二个.then。或者换句话说,如果执行了catch,我不希望第二个.then执行。

这是可能的吗?或者我是否在第一个then中嵌套第二个承诺:

return1stPromise()
  .then(function (data) {
    return if1stPromiseSucceeds(data).then(if2ndPromiseSucceeds);
  })
  .catch(if1stPromiseFails);

此外-任何好的资源如何控制流与承诺,它更像线程?

你所描述的是典型的情况,当我们想对一个异常做出反应,但实际上不处理它,让代码继续运行:

return1stPromise()
  .then(if1stPromiseSucceeds) // returns 2nd Promise
  .catch(() => { if1stPromiseFails(); throw e; })
  .then(if2ndPromiseSucceeds) // execute only if 1st Promise succeeds

您需要重新抛出异常,以便将其标记为"仍未处理"。

这就像同步代码:

try {
  var res = firstResult();
  var res2 = ifFirstPromiseSucceeds(res);
} catch (e) {
    ifFirstPromiseFails();
    throw e; // we reacted to the exception but did not handle it yet.
}
var res3 = ifSecondPromiseSucceeds();

我认为从线程的角度来考虑承诺是很容易混淆的——如果可能的话,找到一个同步的类比总是更容易。

这并不总是可能的,例如,另一种停止承诺链的方式是取消,这有点像带有"我不关心结果"语义的线程中止-你可以在这里阅读它,但我认为对于你的用例来说,它有点过头了,而且不那么好。

我可能会做抛出和捕获,但如果你不想这样做,你总是可以返回一个被拒绝的承诺来绕过下一个then阶段。例如,

new Promise((resolve,reject) => { var rnd = Math.random();
	                              rnd > 0.5 ? resolve(21)
	                                        : reject("promise error");
                                })
    .then(val  => { var rnd = Math.random();
                    if (rnd < 0.5) return Promise.reject("then error");
                    return Promise.resolve(val*2);
                  })
    .catch(err => { console.log(err);
                    return Promise.reject("you won't see this");
                  })
    .then(val  => console.log("Both the promise and the first then stage worked fine and resulted: ", val));

最后一个then阶段回调将只在第一个then阶段的第一个承诺和第二个承诺解析时被调用。