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.
Generator.prototype.next()
: Returns a value generated by theyield
expression.Generator.prototype.return()
: Returns the given value and ends the generator.Generator.prototype.throw()
: Throws an error to the generator.
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}
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();
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
https://github.com/WindrunnerMax/EveryDay
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