1

I'm trying to call a chain of promises sequentially. I would like to pass some state across all the promises. I thought I'd be able to bind() my state but have been unable to get it working. My sample code looks like:

var Promise = require('bluebird');
...
function op1(state) {
    return new Promise(function(resolve, reject) {
        this.num += 1;
        resolve();
    });
}
function op2(state) {
    return new Promise(function(resolve, reject) {
        this.num += 1;
        resolve();
    });
}
function op3(state) {
    return new Promise(function(resolve, reject) {
        this.num += 1;
        resolve();
    });
}

function sequence(tasks, state) {
    var current = Promise.cast();
    for (var k = 0; k < tasks.length; ++k) {
        current = current.thenReturn().then(tasks[k]);
    }
    return current.thenReturn();
}

var state = { yadda: "yadda",
                      num:   0 };
var q = [ op1, op2, op3 ];

var p   = sequence( q, state );
var ret = p()
            .then( function(val) {
                console.log(val);
            })
            .catch ( function(val) {
                console.error(val);
            });

I've tried to simplify the problem to what I see in many example:

op1().bind(state).then(op2).then(op3); 

However, this isn't working either.

I've also tried to change sequence() to the following (among various other things):

var current = Promise.cast().bind(state);

I am still very new to promises. I suspect I am missing something easy. Any advice or help would be much appreciated.

4
  • 2
    I don't think you can bind Promises; you probably need to bind the functions within them. Commented Apr 28, 2016 at 22:11
  • Did you notice you're not using the function arguments anywhere?? Commented Apr 28, 2016 at 22:13
  • @Hamms: It's bluebird, not native promises. Commented Apr 28, 2016 at 22:40
  • I apologize, yes, I forgot to scrub the function arguments when I posted, the function arguments were part of various attempts with bind(), etc. Commented Apr 29, 2016 at 11:10

1 Answer 1

1

Ok, let's see what could be done.

We could start with binding state to each task.

function sequence(tasks, state) {
    var current = Promise.resolve();
    for (var k = 0; k < tasks.length; ++k) {
        const taskWithState = tasks[k].bind(state);
        current = current.then(taskWithState);
    }
    return current;
}

I've used bind to set this inside tasks to state, so:

function op1() {
    // this === state
    return new Promise(function(resolve) {
        // this === window
        this.num += 1;
        resolve();
    });
}

As You might expect, a function that we pass to Promise creates its own context, so this would not point to state like we want it to.

To bypass that issue we could either do an old trick with saving context in a variable (like var that = this) or we could just use arrow functions, which do not create their own context. With that in mind:

function op1() {
    // this === state
    return new Promise(resolve => {
        // this === state
        this.num += 1;
        resolve();
    });
}

All together now

function op1() {
    return new Promise(resolve => {
        this.num += 1;
        resolve();
    });
}

function op2() {
    return new Promise(resolve => {
        this.num += 1;
        resolve();
    });
}

function op3() {
    return new Promise(resolve => {
        this.num += 1;
        resolve();
    });
}

function sequence(tasks, state) {
    let current = Promise.resolve();
    for (let k = 0; k < tasks.length; ++k) {
        const taskWithState = tasks[k].bind(state);
        current = current.then(taskWithState);
    }
    return current;
}

var state = { yadda: "yadda", num:  0 };
var q = [ op1, op2, op3 ];

sequence(q, state)
  .then(() => console.log(state))
  .catch(err => console.error(err));
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks so much for the detailed write up. Your solution worked well. I did try to bind to the "task", but did not realize the this was changed within the Promise callback.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.