最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - chain array of promises with bluebird - Stack Overflow

programmeradmin2浏览0评论

I'm a working my way with promises and I'm stuck with my use case. I have an array of transformer functions (each function is a promise and modifies some JSON structure).

Let me show some code.

Lets say this is my JSON structure (array)

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

transformFunction is definition of transform functions modifying the data a certain way. The two functions adds c and d property to the above JSON structure:

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);
        })
    },
    ...
}

The from a UI user specifies which transformer functions he should use and in what order. Lets say he picked the normal order like this:

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

The transform1 method should modify the data and the result should be passed to transform2 method.

I was looking at: Promise.all but it seems that it does not care for the order of the promises, and most important it needs to pass the previous result to the next promise.

I'm a working my way with promises and I'm stuck with my use case. I have an array of transformer functions (each function is a promise and modifies some JSON structure).

Let me show some code.

Lets say this is my JSON structure (array)

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

transformFunction is definition of transform functions modifying the data a certain way. The two functions adds c and d property to the above JSON structure:

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);
        })
    },
    ...
}

The from a UI user specifies which transformer functions he should use and in what order. Lets say he picked the normal order like this:

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

The transform1 method should modify the data and the result should be passed to transform2 method.

I was looking at: Promise.all but it seems that it does not care for the order of the promises, and most important it needs to pass the previous result to the next promise.

Share Improve this question edited Jun 10, 2015 at 9:02 Alex Kolarski asked Jun 9, 2015 at 13:05 Alex KolarskiAlex Kolarski 3,4251 gold badge27 silver badges35 bronze badges 4
  • 2 I just have to ask, but why would you use promises for this, it's not asynchronous ` – adeneo Commented Jun 9, 2015 at 13:06
  • I simplified it for the question, in the real usecase I can make a db request or ajax call in there. – Alex Kolarski Commented Jun 9, 2015 at 13:07
  • I'm not sure, but from the way you're describing it, it sounds like you just want to pipe data or something. Maybe someone with more experience using Bluebird will answer, I've only used it a little for promisifying middleware etc – adeneo Commented Jun 9, 2015 at 13:09
  • Yes, piping is the effect that I'm looking after, but from array of promises. Thanks for your input – Alex Kolarski Commented Jun 9, 2015 at 13:12
Add a ment  | 

2 Answers 2

Reset to default 5

Note: As adeneo pointed out in the ments, use promises only if you are dealing with asynchronous code.

  1. Create an array of functions which are to be executed. And make sure that they all return a Promise.

  2. Then, you can use Promise.reduce to reduce the initial value to the transformed final value by returning the result of executing current promise returning function, on every iteration.

  3. Finally you can attach a then handler to get the actual value and a catch handler, just in case if the promises are rejected.

Lets say we have two transform functions like this.

Note: I am telling again. You should never use Promises with functions like these. You should use promises only when the functions you are dealing with are really asynchronous.

// 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;
    }));
}

Then you can transform the original value, like this

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);
    });

Output

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

You can chain Promises the way you always do: using .then().

Let's say you have these two transformations:

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

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

In a real scenario, these would be doing asynchronous work. You could just:

increment(1).then(double)

But, you don't know the order or number of transformations. Let's put them into an array, and then() them one by one:

var transformations = [increment, double]

var promise = Promise.resolve(1);

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

You can attach a catch() handler before you start, after you finish or even per-transformation.

This isn't efficient if you're going to apply hundreds of transformations. In that case, you should use reduce() as thefourtheye suggests in his answer.

发布评论

评论列表(0)

  1. 暂无评论