与蓝鸟的承诺链阵列

Posted

技术标签:

【中文标题】与蓝鸟的承诺链阵列【英文标题】:chain array of promises with bluebird 【发布时间】:2015-08-24 07:41:36 【问题描述】:

我正在按照自己的方式履行承诺,但我坚持使用我的用例。 我有一组转换器函数(每个函数都是一个承诺并修改一些 JSON 结构)。

让我展示一些代码。

假设这是我的 JSON 结构(数组)

var data = [a: 1, b:2, a:3, b:4]; 

transformFunction 是转换函数以某种方式修改数据的定义。这两个函数将cd属性添加到上述JSON结构中:

var transformFunctions =  // 

    transform1: function (data)   // This function adds `c` property to each object from `a`
        return new Promise(function (resolve) 
             for (var i = 0; i < data.length; i++) 
                 data[i].c = data[i].a;
             
             return resolve(data);
        )
    ,

    transform2: function (data)   // This function adds `d` property to each object from `c`
        return new Promise(function (resolve) 
             for (var i = 0; i < data.length; i++) 
                 data[i].d = data[i].c;
             
             return resolve(data);
        )
    ,
    ...

来自用户界面的用户指定他应该使用哪些转换器功能以及使用顺序。假设他选择了这样的正常顺序:

var userTransformList = ['transform1', 'transform2'];

transform1 方法应该修改数据并将结果传递给transform2 方法。

我在看:Promise.all 但它似乎不关心承诺的顺序,最重要的是它需要将上一个结果传递给下一个承诺。

【问题讨论】:

我只是想问一下,但是你为什么要为此使用 Promise,它不是异步的` 我为这个问题简化了它,在真正的用例中我可以在那里发出 db 请求或 ajax 调用。 我不确定,但从你描述它的方式来看,听起来你只是想管道数据或其他东西。也许有更多使用 Bluebird 经验的人会回答,我只是将它用于承诺中间件等 是的,管道是我正在关注的效果,但来自一系列承诺。感谢您的意见 【参考方案1】:

注意:正如 adeneo 在 cmets 中指出的那样,只有在处理异步代码时才使用 Promise。

    创建要执行的函数数组。并确保它们都返回一个 Promise。

    然后,您可以使用Promise.reduce,通过在每次迭代中返回当前promise返回函数的执行结果,将初始值减少为转换后的最终值。

    最后你可以附加一个then处理程序来获取实际值和一个catch处理程序,以防promise被拒绝。

假设我们有两个这样的变换函数。

注意:我再说一遍。你永远不应该将 Promises 与这些函数一起使用。仅当您处理的函数确实是异步的时,您才应该使用 Promise。

// Just add a property called `c` to all the objects and return a Promise object
function transform1(data) 
    return Promise.resolve(data.map(function(currentObject) 
        currentObject.c = currentObject.a + currentObject.b;
        return currentObject;
    ));


// Just add a property called `d` to all the objects and return a Promise object
function transform2(data) 
    return Promise.resolve(data.map(function(currentObject) 
        currentObject.d = currentObject.a + currentObject.b + currentObject.c;
        return currentObject;
    ));

然后就可以对原来的值进行变换了,像这样

Promise.reduce([transform1, transform2], function (result, currentFunction) 
        return currentFunction(result);
    , [a: 1, b: 2, a: 3, b: 4])      // Initial value
    .then(function (transformedData) 
        console.log(transformedData);
    )
    .catch(function (err) 
        console.error(err);
    );

输出

[  a: 1, b: 2, c: 3, d: 6 ,  a: 3, b: 4, c: 7, d: 14  ]

【讨论】:

【参考方案2】:

您可以像往常一样链接 Promise:使用 .then()

假设你有这两个转换:

function increment(x) 
    return Promise.resolve(x + 1);


function double(x) 
    return Promise.resolve(2 * x);

在实际场景中,这些将执行异步工作。你可以:

increment(1).then(double)

但是,您不知道转换的顺序或数量。我们把它们放入一个数组中,then()它们一个一个:

var transformations = [increment, double]

var promise = Promise.resolve(1);

for (var i = 0; i < transformations.length; i++)
  promise = promise.then(transformations[i]);

您可以在开始之前、完成之后甚至每次转换时附加 catch() 处理程序。

如果您要应用数百个转换,这效率不高。在这种情况下,您应该使用reduce(),正如thefourtheye 在他的回答中所建议的那样。

【讨论】:

以上是关于与蓝鸟的承诺链阵列的主要内容,如果未能解决你的问题,请参考以下文章

蓝鸟承诺 - 嵌套与拒绝模式

蓝鸟嵌套承诺与每个/传播

猫鼬承诺与蓝鸟和打字稿

蓝鸟承诺未定义?

中途停止承诺链

蓝鸟,承诺,然后()