2018年10月30日 星期二

about js Generator

判斷一個function 是否是generator 的方法

var x  = function * (){yield undefined;}
console.log(x.constructor.name === 'GeneratorFunction')
-------------------------------------------------------------------
The function* declaration (function keyword followed by an asterisk) defines a generator function, which returns a Generator object.
You can also define generator functions using the GeneratorFunction constructor, or the function expression syntax.

Syntax

Section

function* name([param[, param[, ... param]]]) {
   statements
}
name
The function name.
param
The name of a formal parameter for the function.
statements
The statements comprising the body of the function.

Description

Section

Generators are functions which can be exited and later re-entered. Their context (variable bindings) will be saved across re-entrances.

Generators in JavaScript -- especially when combined with Promises -- are a very powerful tool for asynchronous programming as they mitigate -- if not entirely eliminate -- the problems with callbacks, such as Callback Hell and Inversion of Control.
This pattern is what async functions are built on top of.
Calling a generator function does not execute its body immediately; an iterator object for the function is returned instead. When the iterator's next() method is called, the generator function's body is executed until the first yield expression, which specifies the value to be returned from the iterator or, with yield*, delegates to another generator function. The next() method returns an object with a value property containing the yielded value and a done property which indicates whether the generator has yielded its last value as a boolean. Calling the next() method with an argument will resume the generator function execution, replacing the yield expression where execution was paused with the argument from next().
A return statement in a generator, when executed, will make the generator finished (i.e the done property of the object returned by it will be set to true). If a value is returned, it will be set as the value property of the object returned by the generator.
Much like a return statement, an error thrown inside the generator will make the generator finished -- unless caught within the generator's body.
When a generator is finished, subsequent next calls will not execute any  of that generator's code, they will just return an object of this form: {value: undefined, done: true}.

Examples

Section

Simple example

Section

function* idMaker() {
  var index = 0;
  while (index < index+1)
    yield index++;
}

var gen = idMaker();

console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // 3
// ...

Example with yield*

Section

function* anotherGenerator(i) {
  yield i + 1;
  yield i + 2;
  yield i + 3;
}

function* generator(i) {
  yield i;
  yield* anotherGenerator(i);
  yield i + 10;
}

var gen = generator(10);

console.log(gen.next().value); // 10
console.log(gen.next().value); // 11
console.log(gen.next().value); // 12
console.log(gen.next().value); // 13
console.log(gen.next().value); // 20

Passing arguments into Generators

Section

function* logGenerator() {
  console.log(0);
  console.log(1, yield);
  console.log(2, yield);
  console.log(3, yield);
}

var gen = logGenerator();

// the first call of next executes from the start of the function
// until the first yield statement
gen.next();             // 0
gen.next('pretzel');    // 1 pretzel
gen.next('california'); // 2 california
gen.next('mayonnaise'); // 3 mayonnaise

Return statement in a generator

Section

function* yieldAndReturn() {
  yield "Y";
  return "R";
  yield "unreachable";
}

var gen = yieldAndReturn()
console.log(gen.next()); // { value: "Y", done: false }
console.log(gen.next()); // { value: "R", done: true }
console.log(gen.next()); // { value: undefined, done: true }

Generators are not constructable

Section

function* f() {}
var obj = new f; // throws "TypeError: f is not a constructor

Generator defined in an expression

Section

const foo = function* () {
  yield 10;
  yield 20;
};

const bar = foo();
console.log(bar.next()); // {value: 10, done: false}
 
-------------------------------------------
 
The Generator object is returned by a generator function and it conforms to both the iterable protocol and the iterator protocol.

Syntax

區段

function* gen() { yield 1; yield 2; yield 3; } var g = gen(); // "Generator { }"

Methods

區段

Generator.prototype.next()
Returns a value yielded by the yield expression.
Generator.prototype.return()
Returns the given value and finishes the generator.
Generator.prototype.throw()
Throws an error to a generator (also finishes the generator, unless caught from within that generator).

Example

區段

An infinite iterator

區段

function* idMaker() {  
    var index = 0;  
    while(true) yield index++; 
}  

var gen = idMaker(); // "Generator { }" console.log(gen.next().value); // 0 

console.log(gen.next().value); // 1 console.log(gen.next().value); // 2 // ...

Legacy generator objects

區段

Firefox (SpiderMonkey) also implemented an earlier version of generators in JavaScript 1.7, where the star (*) in the function declaration was not necessary (you just use the yield keyword in the function body). However, legacy generators support has been removed since Firefox 58 (released on January 23, 2018) (bug 1083482).

Legacy generator methods

區段

Generator.prototype.next()
Returns a value yielded by the yield expression. This corresponds to next() in the ES2015 generator object.
Generator.prototype.close()
Closes the generator, so that when calling next() an StopIteration error will be thrown. This corresponds to the return() method in the ES2015 generator object.
Generator.prototype.send()
Used to send a value to a generator. The value is returned from the yield expression, and returns a value yielded by the next yield expression. send(x) corresponds to next(x) in the ES2015 generator object.
Generator.prototype.throw()
Throws an error to a generator. This corresponds to the throw() method in the ES2015 generator object.

Legacy generator example

區段

function* fibonacci() { var a = yield 1; yield a * 2; }  

var it = fibonacci(); 

console.log(it); // "Generator { }" console.log(it.next()); // 1 

console.log(it.send(10)); // 20 console.log(it.close()); // undefined 
console.log(it.next()); // throws StopIteration (as the generator is now closed)