Generator Function

The generator generator is a new data type introduced in the ES6 standard. A generator looks like a function but can return multiple times by using the yield keyword. It suspends the function's execution flow, providing the possibility to change the execution process and thus providing a solution for asynchronous programming.

Methods

  • Generator.prototype.next(): Returns a value generated by the yield expression.
  • Generator.prototype.return(): Returns the given value and ends the generator.
  • Generator.prototype.throw(): Throws an error to the generator.

Instance

Using the function* declaration defines a generator function, which returns a Generator object. It can be understood as a state machine encapsulating multiple internal states. Executing the generator function returns an iterator object.
Calling a generator function does not immediately execute the statements inside it; instead, it returns an iterator object that points to the internal state object. When the next() method of this iterator is called for the first time (subsequently), the statements inside it will execute up to the first (subsequent) appearance of yield, and the value following yield will be returned by the iterator. The pointer will then start executing from the beginning of the function or from the last suspended position to the next yield. If yield* is used, it means transferring the execution to another generator function (the current generator is suspended).
The next() method returns an object containing two properties: value, representing the return value of the current yield expression, and done, a boolean indicating whether there are subsequent yield statements in the generator function, i.e., whether the generator function has finished execution and returned.

function* f(x) {
    yield x + 10;
    yield x + 20;
    return x + 30;
}
var g = f(1);
console.log(g); // f {<suspended>}
console.log(g.next()); // {value: 11, done: false}
console.log(g.next()); // {value: 21, done: false}
console.log(g.next()); // {value: 31, done: true}
console.log(g.next()); // {value: undefined, done: true} // It can go on indefinitely with next(), but value is always undefined and done is always true

When calling the next() method, if an argument is passed, it will be passed to the variable on the left of the last executed yield statement.

function* f(x) {
    var y = yield x + 10;
    console.log(y);
    yield x + y;
    console.log(x,y);
    return x + 30;
}
var g = f(1);
console.log(g); // f {<suspended>}
console.log(g.next()); // {value: 11, done: false}
console.log(g.next(50)); // {value: 51, done: false} // y is assigned the value 50
console.log(g.next()); // {value: 31, done: true} // x,y 1,50
console.log(g.next()); // {value: undefined, done: true}

If the return value for the return method is explicitly specified, that value is returned and the traversal of the generator function ends. If the return value for return is not explicitly specified, undefined is returned.

function* f(x) {
    yield x + 10;
    yield x + 20;
    yield x + 30;
}
var g = f(1);
console.log(g); // f {<suspended>}
console.log(g.next()); // {value: 11, done: false}
console.log(g.next()); // {value: 21, done: false}
console.log(g.next()); // {value: 31, done: false} // Note that done here is false
console.log(g.next()); // {value: undefined, done: true}

The yield* expression indicates that yield returns an iterator object, used within a Generator function to call another Generator function.

function* callee() {
    yield 100;
    yield 200;
    return 300;
}
function* f(x) {
    yield x + 10;
    yield* callee();
    yield x + 30;
}
var g = f(1);
console.log(g); // f {<suspended>}
console.log(g.next()); // {value: 11, done: false}
console.log(g.next()); // {value: 100, done: false}
console.log(g.next()); // {value: 200, done: false}
console.log(g.next()); // {value: 31, done: false}
console.log(g.next()); // {value: undefined, done: true}

Use Cases

Synchronous Representation of Asynchronous Operations

var it = null;
function f(){
    var rand = Math.random() * 2;
    setTimeout(function(){
        if(it) it.next(rand);
    },1000)
}
function success(r1,r2,r3){
    console.log(r1,r2,r3); // 0.11931234806372775 0.3525336021860719 0.39753321774160844
}
// Convert nested tasks into linear tasks
function* g(){ 
    var r1 = yield f();
    console.log(r1);
    var r2 = yield f();
    console.log(r2);
    var r3 = yield f();
    console.log(r3);
    success(r1,r2,r3);
}

it = g();
it.next();

Organization

Long Polling: https://www.cnblogs.com/wjyz/p/11102379.html Delayed Execution Infinite Sequence: http://www.hubwiz.com/exchange/57fb046ce8424ba757b8206d Fibonacci Sequence: https://www.liaoxuefeng.com/wiki/1022910821149312/1023024381818112 Iterator: https://zhuanlan.zhihu.com/p/24729321?utm_source=tuicool&utm_medium=referral Linear Approach: https://blog.csdn.net/astonishqft/article/details/82782422?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

Daily Challenge

https://github.com/WindrunnerMax/EveryDay

References

https://www.runoob.com/w3cnote/es6-generator.html https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/function* https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Generator