e_m0ney
e_m0ney

Reputation: 980

How to wait on completion of a whole chain of Promises in Javascript ECMAScript2015 (es6)

Pretty new to es6 and curious to know whether now with Promises, I can do away with future.wait()

I have a method called execute(), which starts a chain of promises. I have two requirements of this method:

Here is my sample code:

/* Require dependencies */
require('babel/polyfill');

class PromiseWaiter {
  /* Constructor */
  constructor() {
  }

  /* Methods */
  execute() {
    let _this = this;

    runPromiseGenerator(function *promiseGenerator() {
      yield _this.asyncMethod1();
      yield _this.asyncMethod2();
      yield _this.asyncMethod3();
    });

    return true;
  }

  asyncMethod1() {
    return returnDummyPromise('method 1', 800);
  }
  asyncMethod2() {
    return returnDummyPromise('method 2', 200);
  }
  asyncMethod3() {
    return returnDummyPromise('method 3', 200);
  }
}

var runPromiseGenerator = function(generator) {
  var it = generator(), ret;

  // asynchronously iterate over generator
  (function iterate(val) {
    ret = it.next(val);

    if (!ret.done) {
      // poor man's "is it a promise?" test
      if ("then" in ret.value) {
        // wait on the promise
        ret.value.then(iterate);
      }
      // immediate value: just send right back in
      else {
        // avoid synchronous recursion
        setTimeout( function(){
          iterate(ret.value);
        }, 0);
      }
    }
  })();

};

var returnDummyPromise = function(methodName, timeout) {
  console.log('starting %s', methodName);
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      console.log('finished %s', methodName);
      resolve();
    }, timeout);
  })
};

module.exports = PromiseWaiter;

Here is what I run on the node console to test & the current output:

> p = new PromiseWaiter()
{}
> p.execute()
starting method 1
true
> finished method 1
starting method 2
finished method 2
starting method 3
finished method 3

What I want to see is:

> p = new PromiseWaiter()
{}
> p.execute()
starting method 1
finished method 1
starting method 2
finished method 2
starting method 3
finished method 3
true
>

In the past I would have done this using

fut = new Future();
// set off chain passing future
future.wait();

Wanted to pick the brains of the best and brightest out there.

Thanks in advance for your time! Elliott

Upvotes: 1

Views: 164

Answers (1)

loganfsmyth
loganfsmyth

Reputation: 161457

You'll need to return a promise that will resolve when the generator has completed. I'd really recommend using an existing implementation like co however if you wanted to expand your own implementation:

var runPromiseGenerator = function(generator) {
  return new Promise(function(resolve, reject){
    var it = generator(), ret;

    // asynchronously iterate over generator
    (function iterate(val) {
      try {
        ret = it.next(val);

        if (!ret.done) {
          Promise.resolve(ret.value).then(iterate, reject);
        }
        else {
          resolve(ret.value);
        }
      }
      catch (e){
        reject(e);
      }
    })();
  });
};

then you can alter your execute to be

execute() {
  let _this = this;

  return runPromiseGenerator(function *promiseGenerator() {
    yield _this.asyncMethod1();
    yield _this.asyncMethod2();
    yield _this.asyncMethod3();
  });
}

and do

p.execute().then(function(){
  // done
});

Alternatively, you can use your existing function to then call it, e.g.

runPromiseGenerator(function *promiseGenerator() {
  yield p.execute();

  // do something after execution
});

Upvotes: 1

Related Questions