0

suppose I have following functions:

var f1 = function() {
    console.log('running f1');
    return new Promise(function(res, rej) {
        setTimeout(() => res('resolved_1!'), 1000);
    });
};

var f2 = function(a) {
    console.log('running f2 with ' + a);
    return new Promise(function(res, rej) {
        setTimeout(() => res('resolved_2!'), 2000);
    });
};

var f3 = function() {
    console.log('running f3');
    return new Promise(function(res, rej) {
        setTimeout(() => res('resolved_3!'), 3000);
    });
};

I can run them with:

let t1 = +new Date;
Promise.all([
    f1().then(a => {
        return f2(a);
    }),
    f3()
]).then((result) => {
    let t2 = +new Date;
    console.log(t2 - t1);
});

And it takes roughly 3 seconds.

Now I want to run these functions using generators:

let t1 = +new Date;
let result = yield [f1(), f3()];
yield f2(result[0]);
let t2 = +new Date;
console.log(t2 - t1)

Since I need resolved value of f1 to call f2 I shall wait for f1 to complete. This takes 5 seconds. How can I get the same 3 seconds but using generators?

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Javad M. Amiri
  • 594
  • 5
  • 20
  • Your second case doesn't make sense to me. Can you give reproducible example? – thefourtheye Mar 08 '16 at 16:30
  • You would need a dispatcher that special case yielded values that are promises. Also, you'd still need to `Promise.all([f1(), f3()]` – MinusFour Mar 08 '16 at 16:39
  • Generators are not a replacement for promises, they are an aid to help with writing promise code. – Bergi Mar 08 '16 at 16:41
  • @thefourtheye you must call second part with utilities such as "co": https://github.com/tj/co. I'm using this inside a generator function which is ran using "co-express"; – Javad M. Amiri Mar 08 '16 at 16:41
  • What generator runner function are you using? Which promise library? – Bergi Mar 08 '16 at 16:42
  • @Bergi, I'm using "co-express" and actual promises are mongo promises. Here I simplified promises with ES6 Promises. In reality racing is among three different mongo queries. – Javad M. Amiri Mar 08 '16 at 16:44

1 Answers1

1

This takes 5 seconds.

See Slowdown due to non-parallel awaiting of promises in async generators.

How can I get the same 3 seconds but using generators?

You just have to express the same control flow:

let t1 = +new Date;
let result = yield [f1().then(f2), f3()];
let t2 = +new Date;
console.log(t2 - t1)

If you want to avoid then for some reason, and use generators instead, it would have to be

let t1 = +new Date;
let result = yield [co(function*() {
    var a = yield f1();
    return yield f2(a); // yield is optional here
}), f3()];
let t2 = +new Date;
console.log(t2 - t1)
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • shouldn't it be `Promise.all([co.., f3()])`? Or does the dispatcher pass that to Promise.all anyway? – MinusFour Mar 08 '16 at 16:53
  • 1
    @MinusFour: Yes, it could be. However OP uses `co`, which has [many kinds of "yieldables"](https://github.com/tj/co#yieldables) (not only promises). I could as well have omitted the call to `co` and passed the generator function itself. At some point, that's not being clean any more though. – Bergi Mar 08 '16 at 16:56
  • @JavadM.Amiri: I'd hope the first one does as well? Is anything wrong there? – Bergi Mar 08 '16 at 20:02
  • @Bergi, Nothing is wrong with the first. Indeed I've tried it before but in my case, since f1 returns a generator (**f1** is a generator function which performs some mongo queries, aggregate them and then return a mongo query i.e. Model.find()) it does not work. So, I cannot call then on a generator. – Javad M. Amiri Mar 09 '16 at 07:43
  • @JavadM.Amiri: I recommend using `co.wrap` on all your generator functions so that they return promises right away – Bergi Mar 09 '16 at 15:51
  • @Bergi, sure! I'll consider refactoring my code using `co.wrap`. – Javad M. Amiri Mar 10 '16 at 10:22