承诺控制流(es2015),具有复杂的参数依赖性

时间:2016-12-07 06:49:56

标签: javascript promise ecmascript-6 control-flow

"回调地狱" 等类似的替代方案相比,有很多方法可以通过ES2015承诺来实现良好的控制流程。那里有很多例子。

但是,当控制流中每个步骤的参数依赖于上一步的返回/已解决值时,更难找到一个好的语法。实际的用例通常有点复杂,因此简化的示例语法可能看起来不那么难看,但它使解释和讨论更容易。

所以,问题是 如何制作简单(易读且易于维护)但灵活的方法来解决此类案件

实施例

控制流程中的三个操作。每个都是一个返回Promise的函数。

function firstOperation(arg1) {
    return new Promise(...);
}

function secondOperation(firstResponse) {
    return new Promise(...);
}

function thirdOperation(firstResponse, secondResponse) {
    return new Promise(...);
}

更简单的控制流程

如果每一步都只依赖于前一步,它可能看起来像这样:

firstOperation('foo')
    .then(res1 => secondOperation(res1))
    .then(res2 => thirdOperation(res2));

甚至更简单:

firstOperation('foo')
    .then(secondOperation)
    .then(thirdOperation);

没问题。但在这种情况下,thirdOperation需要前两个操作的参数。

未来

在ES8中,我猜这看起来像是:

const res1 = await firstOperation('foo');
const res2 = await secondOperation(res1);
const res3 = await thirdOperation(res1, res2);

现在

我想使用已完成的标准,因此我希望通过ES2015语法或可能的promise / generator库为这类案例找到最佳解决方案。

可能(但不是非常简单/可读)的解决方法:

firstOperation('foo')
    .then(res1 => secondOperation(res1)
        .then(res2 => thirdOperation(res1, res2))
    );

让它成为一种承诺地狱"这是有效的,但在更复杂的情况下(不止一个级别)会变得丑陋,难以阅读/维护。

另一种解决方案:

firstOperation('foo')
    .then(res1 => secondOperation(res1)
        .then(res2 => ({ res1, res2 })))
    .then(({ res1, res2 }) => thirdOperation(res1, res2));

与前一个相比,唯一的好处是,如果有超过三个操作,它们都可以在同一级别上调用,而不是每次进一步缩进一个级别。并且在每次操作之后,结果将与其他操作合并为"上下文对象"保持所有结果。

建议?

所以,直到出现标准化方式(可能是ES8),我想使用某种承诺/生成器库是一种可接受的解决方案。我最希望的是,我不需要自己触摸功能。就像仍然让他们(示例中的firstOperationsecondOperationthirdOperation)以正常方式获取参数,并返回一个直接用值解析的promise,而不是将它们重写为能够适应不同的控制流程用例。

解决此类案件的建议?

2 个答案:

答案 0 :(得分:2)

你可以这样做:

const res1 = firstOperation('foo');
const res2 = res1.then(secondOperation);
const res3 = Promise.all([res1, res2])
    .then(args => thirdOperation(...args));

答案 1 :(得分:-1)

我通常在promise链之前声明变量并将结果存储在那里,所有调用都可以访问它们。它有效,不需要增加缩进/更深的练级,并且它不需要你改变你的功能参数。

let firstResponse;

firstOperation(userId)
.then(firstResp=>{
    firstResponse = firstRestp;
    return secondOperation(firstResponse);
 })
.then(secondResponse=>{
    return thirdOperation(firstResponse, secondResponse);
});

修改

这个answer in the linked duplicate question指出了这种方法的一些缺点。例如,变量可能在填充之前使用。