- The they differ from normal functions with respect to the "run to completion" expectation.
- With ES6 generators, we have a different kind of function, which may be paused in the middle, one or many times, and resumed later
- yield() pause the generator, the generator pause itself, some other object need to resume the generator.
ES6 generator functions are "cooperative" in their concurrency behavior.
This ideal for creating functions that should be exited and continued later: we run the generator and yield when we restart the generator again, we will send a value back in, and whatever we send in will be the computed result of that yield ___ expression.
Generator objects are both iterator and iterable.
Provides a solutions for a endless callback problem
- it is now possible to suspend code execution
- Factory for special type of function declared using function* or function *
- Can be exited at any point using: yield
- Resumes at same point and same state if invoked back again
- Provides 2-way communication:
We trigger the generator, the yield value it sends out, generator is paused, later (at any time), generator is trigger again thnen is restarted and will give a value back.
- A generator function can stop and be restarted, as many times as you choose.
- Onces a generator has yield-paused itself, it cannot resume on its own.
yield - yield expression will PAUSE the execution
next() - Continue the execution
Definition
// both are valids
function* foo(){
//...
}
function *foo(){
// ..
}
Iterator objects are objects that implement the Iterator interface. This simple requires the implementation of a .next() method: this method returns: { value, done } object
// generator function - declared with *
// To step through the values of that *foo() generator function, we need an iterator to be constructed
// yield PAUSE execution
function hello1(){alert("hello1");}
function hello2(){alert("hello2");}
function *foo() {
yield hello1();
yield hello2();
yield 3;
yield 4;
yield 5;
return 'no more yelds'
}
// create and iterator object
var it = foo();
console.log(it.next().value);
it.next(); // The next method is a function that returns a value
// generator function can take parameters
function *generator (name) {
return name + ', said hello';
}
// iterator object - passing 'Leo'
let iterator = generator('Leo');
iterator.next(); // { value: "Leo, said hello", done: true }
Any object that contains a [Symbol.iterator] method is an iterable object.
[Symbol.iterator]
// it is a method that returns an iterato because you may want to iterate over the same data source multiple times,
let iterable = [1, 2, 3, 4];
let iterator1 = iterable[Symbol.iterator]();
let iterator2 = iterable[Symbol.iterator]();
iterator1.next(); // { value: 1, done: false }
iterator2.next(); // { value: 1, done: false }
iterator2.next(); // { value: 2, done: false }
iterator2.next(); // { value: 3, done: false }
iterator1.next(); // { value: 2, done: false }
An object from implementing BOTH Iterable and Iterator interfaces
// generator function - declared with *
function *foo() {
yield 1;
return 2;
}
// create and iterator object
var it = foo();
console.log( it.next() ); // { value:1, done:false }
console.log( it.next() ); // {value: 2, done: true}
console.log( it.next() ); // { value:undefined, done:true }
console.log( it.next() ); // { value:undefined, done:true }
console.log( it.next().value ); // undefined
console.log( it.next().done ); // true
Eg1: ES6 generators: value, done
function *counter(){
var index = 0;
while(true) yield index++;
}
// create and iterator object
var c = counter();
console.log( c.next() ); // Object {value: 0, done: false}
console.log( c.next().value ); // 1
console.log( c.next().done ); // false
eg2: ES6 generators: value, done
function *foo(x) {
var y = 2 * (yield (x + 1));
var z = yield (y / 3);
return (x + y + z);
}
var it = foo( 5 );
// note: not sending anything into <code>next()</code> here
console.log( it.next() ); // { value:6, done:false }
console.log( it.next( 12 ) ); // { value:8, done:false }
console.log( it.next( 13 ) ); // { value:42, done:true }
function foo2(){
alert ('hello2');
}
function *foo(){
yield 1;
yield foo2();
}
var t1 = foo();
t1.next(); // 1
t1.next(); // hello2
t1.next(); // undefined
## Error Handling (generator handle the error)
function *foo() {
try {
var x = yield 10;
console.log( "x: " + x );
}
catch (err){
console.log( "Error: " + err ); // Uncaught an error here!
}
}
var it = foo();
var res = it.next();
console.log(res); // { value:10, done:false }
it.throw( "an error here!" );
function *foo() {
var x = yield 10;
var y = x.doTheTheMath();
yield y;
}
var it = foo();
vat res = it.next();
console.log(res); // { value:10, done:false }
try {
it.next( 100 ); // `100` won't have `doTheTheMath()`
}
catch (err){
console.log( err ); // TypeError (from `doTheTheMath()` call)
}
function *foo() {
yield " name ";
yield " is ";
}
function *poo(){
yield " my ";
}
function *bar() {
yield "Hello";
yield *poo(); // `yield *` delegates iteration control to `poo()`
yield *foo(); // `yield *` delegates iteration control to `foo()`
yield " Leo "; // {value: undefined, done: true}
}
var n = [];
for ( var v of bar() ) {
var n.push(v);
console.log( v );
}
// same as running with iterator
var x = bar();
console.log( x.next() ); // {value: undefined, done: true}
what-are-generators (tobyho.com) es6-generators (davidwalsh)