6

在使用 Promise 编码时,访问来自很久以前的 Promise 链中的数据的正确模式是什么?

例如:

do_A.then(do_B).then(do_C).then(do_D).then(do_E_WithTheDataComingFrom_A_And_C_OnlyWhen_D_IsSuccesfullyCompleted)

我当前的解决方案:通过链传递单个 JSON 结构,并让每个步骤填充它。对此有何看法?

4

2 回答 2

3

我认为没有一个“正确”的模式。您的解决方案听起来很整洁,但是,它有点紧密耦合。它可能对您的情况很有用,但我认为它作为一般模式存在一些问题:

  1. 参与步骤需要就收集器对象的结构达成一致。

  2. 每一步都需要至少参与对象的转发,如果链很长并且对先前数据的需要偶尔发生,这可能会变得乏味。这对于插入不是您编写的步骤也很不灵活(链接并不总是线性发生)。

  3. 换一种说法:除非 do_A|B|C|D 和 do_E 在您的控制之下,否则您需要用样板将它们包装起来,以将您的收集器对象存储在闭包中,并在函数的自然输入和结果之间进行转换,因为这些功能不会“融入”您的模式。

  4. 另一方面,如果函数其中,那么步骤之间的数据依赖关系实际上已经隐藏在函数内部。这可能看起来很干净,但它可能成为维护问题。例如:如果这是一个团队项目,那么有人可能认为他们可以重新排序您的步骤,而在调用模式中没有任何线索 do_E 需要什么输入。

我建议使用闭包更直接的方法:

var a, c;

do_A()
.then(function(result) { a = result; return do_B(); })
.then(do_C)
.then(function(result) { c = result; return do_D(); })
.then(function() {
   return do_E_WithTheDataComingFrom_A_And_C_OnlyWhen_D_Succeeds(a, c);
})
.catch(failed);

没有要定义的收集器对象;do_A|B|C|D 和 do_E 可以是通用函数,无需了解任何模式;除非依赖返回的数据(do_B 和 do_D),否则没有样板;并且数据相关性(a 和 c)是明确的。

于 2015-01-08T06:15:44.113 回答
2

是的,这是将状态与动作链接起来的正确方法。

链接.then语句非常常见,通常是我们在管道周围时的构建块。它是 Promise 的核心。

你所做的既正确又惯用。


对于好奇的精神,让我们展示一下。

为了验证这一点——我们可以检查 Promise 规范。

我们要验证:

  1. 它连锁
  2. 在拒绝的情况下,它不会调用链接中的处理程序 then
  3. then它以相同的原因拒绝返回的下一个承诺
  4. 它按顺序执行并传递返回值。

让我们使用规范按顺序验证这些- 特别是.then

1.它连锁

7.1 然后必须返回一个承诺 [3.3]。

太好了,让我们验证它是否也链接到 fullfillment

如果 onFulfilled 或 onRejected 返回值 x,则运行 Promise Resolution Procedure >[[Resolve]](promise2, x)。

太好了,所以我们知道当我们的 Promise 解决或拒绝时,我们的then处理程序会使用适当的参数调用。因此,假设解决了,.then(do_A).then(do_B)它将始终有效。do_A

2. 在拒绝的情况下,它不会调用链式 then 中的处理程序

7.iv. 如果 onRejected 不是函数并且 promise1 被拒绝,则 promise2 必须以同样的理由被拒绝。

太好了,所以如果它在那里,它会拒绝并调用onRejected,如果它不存在,它会链接。

then3.以同样的理由拒绝下一个返回的promise

我们刚刚在 2 中介绍了这一点。

4. 依次传递返回值执行。

那又是

如果 onFulfilled 或 onRejected 返回值 x,则运行 Promise Resolution Procedure [[Resolve]](promise2, x)。

因此,如果您设置 onFulfilled,它将运行解析过程。解决过程本身规定:

承诺解决过程是一个抽象操作,将承诺和值作为输入,我们将其表示为 [[Resolve]](promise, x)。如果 x 是 thenable,它会尝试让 Promise 采用 x 的状态,假设 x 的行为至少有点像 Promise。否则,它以值 x 履行承诺。

如果/当使用值 y 调用 resolvePromise 时,运行 [[Resolve]](promise, y)。

其中 y 是 x 的返回值。

伟大的!所以它有效。

于 2013-12-03T14:24:47.957 回答