Skip to content

Latest commit

 

History

History
249 lines (205 loc) · 6.73 KB

2.7-Generators.md

File metadata and controls

249 lines (205 loc) · 6.73 KB

2.7-Generators: yield(pause), next()(resume), *function()

  • 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

What is a Generator?

  • 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.

New ES6 Generator keywords and native Iterator:

 yield - yield expression will PAUSE the execution
 next() - Continue the execution

Definition

// both are valids
function* foo(){
  //...
}

function *foo(){
  // ..
}

"Iterator" Interface: .next()

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

// 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 }

"Iterable" interface

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 }

Iterable Iterator objects

An object from implementing BOTH Iterable and Iterator interfaces

Generator example

Same example but returning a value

// 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 }

Eg2: ES6 generators: send

Use generators iterators changing methods

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!" );

Error handling (iterator handle the error)

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)
}

Delegating Generators

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}

Some frameworks already using Generators:

CO Framework KAO Framework

More about them:

what-are-generators (tobyho.com) es6-generators (davidwalsh)

Further information:

ecma-international.org/

⬆ back to top