Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript ES6 generator async

I need to run generator async (I need to have result in console 1,2,3,4,5 cause now I have 4,1,2,3,5) any one can help me? I need run task and wait when previous task is finished before it run next task. I need to use (if possible: only) generators (or generator + promise?)

Here my code

/*jshint esnext: true */
function show(msg) {
  var _msg = msg;
  setTimeout(function() { console.log(_msg);}, 2000);
}

function show2(msg) {
  console.log(msg);
}

var stack = [];

// add some function to stack
stack.push(function() { show(1); });
stack.push(function() { show(2); });
stack.push(function() { show(3); });
stack.push(function() { show2(4); });
stack.push(function() { show(5); });

function* generator1() {
  for(var key of stack) {
    yield key();
  }
}
var gen = generator1();
gen.next();
gen.next();
gen.next();
gen.next();
gen.next();
like image 977
axlpl Avatar asked May 27 '15 00:05

axlpl


People also ask

Are generators async in JavaScript?

Async generator functions differ from async functions and generator functions in that they don't return a promise or an iterator, but rather an async iterator. You can think of an async iterator as an iterator whose next() function always returns a promise.

Can generator function be async?

The AsyncGenerator object is returned by an async generator function and it conforms to both the async iterable protocol and the async iterator protocol. Async generator methods always yield Promise objects.

Does ES6 support async await?

Async and Await both are considered as special keywords which are provided by ES6 in order to perform some asynchronous data operations. Even synchronous operations could also be performed using these keywords.

Does async await use generators?

Async/await makes it easier to implement a particular use case of Generators. The return value of the generator is always {value: X, done: Boolean} whereas for async functions, it will always be a promise that will either resolve to the value X or throw an error.


2 Answers

This can be done purely with a generator. Here's an example of one approach, in which we move the .next() into the timeout itself in order to ensure it doesn't occur early. Additionally, the generator now returns the function off the stack instead of executing it, because you can't call .next() on a generator from within the execution of the generator itself.

It's worth noting here that this probably isn't the way I'd do this 'in the wild'; I'd include promises. But you asked if it could be done with just a generator - the answer is 'yes'.

function show(msg) {
  var _msg = msg;
  setTimeout(function() { 
      console.log(_msg);
      execute();
  }, 2000);
}

function show2(msg) {
  console.log(msg);
  execute();
}

var stack = [];

function execute() {
  var fn = gen.next().value;
  if (fn) fn();
}

// add some function to stack
stack.push(function() { show(1); });
stack.push(function() { show(2); });
stack.push(function() { show(3); });
stack.push(function() { show2(4); });
stack.push(function() { show(5); });

function* generator1() {
  for(var key of stack) {
    yield key;
  }
}
var gen = generator1();
execute();

http://jsfiddle.net/smmccrohan/k271gz7o/

like image 158
S McCrohan Avatar answered Oct 11 '22 06:10

S McCrohan


There are many "task running" functions for this, you can even write your own. But you will have to use Promises for this, and not setTimeout. Here is a quick example:

function delay (ms, val) {
  return new Promise(function (res) {
    setTimeout(res, ms || 1000, val || Math.random());
    });
  }

function* run () {
  yield delay();
  console.log(yield delay());
  yield delay();
  console.log('foo'); // sync calls anywhere in between
  console.log(yield delay());
  }

function async(gen){ "use strict";
    gen = gen();
    return Promise.resolve().then(function cont(a){
        var n = gen.next(a),
            v = Promise.resolve(n.value);
        if(n.done) return v; // a `return`
        return n.value.catch(gen.throw.bind(gen)).then(cont);
    });
};

async(run);

Basically, we call the next method of the generator, wait for it to complete, and then fire the next method again, and recurse until generator halts.

Bluebird has a more fault-proof function called Promise.coroutine.

Task.js: http://taskjs.org/ provides a function specially for this.

Hope that helps!

like image 20
jarvis Avatar answered Oct 11 '22 08:10

jarvis