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();
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.
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.
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.
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.
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/
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With