使用Bluebird实现Promise链式数组

5
我正在使用 Promise 来处理问题,但在使用案例中卡住了。我有一个转换器函数数组(每个函数都是 Promise 并修改某些 JSON 结构)。
让我展示一些代码。
假设这是我的 JSON 结构(数组)。
var data = [{a: 1, b:2}, {a:3, b:4}]; 

"transformFunction"是定义转换函数以某种方式修改数据的函数。这两个函数向上述JSON结构添加了"c"和"d"属性:
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,但它似乎不关心承诺的顺序,最重要的是它需要将上一个结果传递给下一个承诺。

2
我只是想问一下,为什么你会在这里使用 Promise,它不是异步的。 - adeneo
我为了这个问题简化了它,在实际用例中,我可以在其中进行数据库请求或ajax调用。 - Alex Kolarski
我不确定,但从你的描述方式来看,似乎你只是想要管道传输数据之类的东西。也许有更多使用Bluebird经验的人会回答,我只是在一些中间件上使用过它进行promisifying。 - adeneo
是的,管道是我想要的效果,但是从承诺数组中获取。感谢您的输入。 - Alex Kolarski
2个回答

5

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

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

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

  3. 最后,您可以附加一个 then 处理程序以获取实际值和一个 catch 处理程序,以防万一 Promise 被拒绝。

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

注意:我再说一遍。您不应该将这些函数与 Promise 一起使用。只有在您处理的函数真正是异步时才应使用 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 } ]

4
你可以像往常一样使用 .then() 来链式处理 Promise。
假设你有以下两个转换操作:
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()处理程序。

如果您将应用数百个转换,则这并不高效。在这种情况下,您应该像thefourtheye在他的答案中建议的那样使用reduce()


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接