generator
Basics
- The generator has the ability to pause and resume code execution within a function block.
- Create generator:
//The asterisk identifying the generator function is not affected by the spaces on both sides function* generator(){ ... }
- Note: arrow functions cannot be used to define generator functions
- Calling the generator function will generate a generator object. The generator object is suspended at the beginning. Similar to the iterator, the generator object also implements the iterator interface and has the next() method. Calling the next() method can make the generator start or resume execution
yield
- The yield keyword allows the generator to stop and start execution. The generator will execute normally before encountering the yield keyword. After encountering this keyword, it will stop, and the state of the function scope will be retained. The stopped generator function can only resume execution by calling the next() method
- The yield keyword can only be used inside the generator. If it is used elsewhere, an error will be thrown
// invalid function* generator(){ function a(){ yield; } }
Realize input and output
- The yield keyword that last suspended the generator function receives the first value passed to the next() method
function* generator(initial) { console.log(initial); console.log(yield); console.log(yield); } let generatorObj = generator('foo'); generatorObj.next('bar'); //foo the first value passed in will not be called because the first time next() is to execute the generator function generatorObj.next('test'); //test generatorObj.next('new'); //new
- For both input and output
function* generator() { return yield 'test'; } let generatorObj = generator(); console.log(generatorObj.next()); //value: 'test', done: 'false' console.log(generatorObj.next('new')); //value: 'new', done: 'true'
Generate iteratable objects
Using asterisks to enhance yield's behavior allows him to iterate over one iteratible object, producing one value at a time
function* generator() { yield*[1, 2, 3]; } for (const x of generator()) { console.log(x); }
Early termination generator
Both the return() and throw() methods can be used to force the generator to close
-
return(): it cannot be recovered after it enters the closed state. Subsequent calls to next() will display the state of done:true, and any return value provided will not be stored or propagated
function* generator() { for (const x of [1, 2, 3]) { yield x; } } const g = generator(); console.log(g.next()); // { value: 1, done: false } console.log(g.return(10)); // { value: 10, done: true } console.log(g.next()); // { value: undefined, done: true } console.log(g.next()); // { value: undefined, done: true }
-
throw(): a provided error will be injected into the generator object during pause. If the error is not handled, the generator will close; If this error is handled inside the generator function, the generator will not close and can resume execution. The error handling will skip the corresponding yield
function* generator() { for (const x of [1, 2, 3]) { yield x; } } const g = generator(); console.log(g); // generator {<suspended>} try { g.throw('error'); } catch (e) { console.log(e); // error } console.log(g); // generator {<closed>}
function* generator() { for (const x of [1, 2, 3]) { try{ yield x; }catch(e){} } } const g = generator(); console.log(g.next()); // { value: 1, done: false } g.throw('error'); console.log(g.next()); // { value: 3, done: false }