admin管理员组文章数量:1391934
I read these line of codes from an article and they showed the work flow of function generator.
var foo, f;
foo = function* () {
console.log('generator 1');
console.log('yield 1', yield 'A');
console.log('generator 2');
console.log('yield 2', yield 'B');
console.log('generator 3');
};
f = foo();
console.log('tick 1');
console.log(f.next('a'));
console.log('tick 2');
console.log(f.next('b'));
console.log('tick 3');
console.log(f.next('c'));
console.log('tick 4');
console.log(f.next('d'));
This is the log in the terminal:
tick 1
generator 1
{ value: 'A', done: false }
tick 2
yield 1 b
generator 2
{ value: 'B', done: false }
tick 3
yield 2 c
generator 3
{ value: undefined, done: true }
tick 4
{ value: undefined, done: true }
But I can not find the way to easily understand this flow, it is kind of weird. If someone has a simple approach to this problem, please help to explain.
I read these line of codes from an article and they showed the work flow of function generator.
var foo, f;
foo = function* () {
console.log('generator 1');
console.log('yield 1', yield 'A');
console.log('generator 2');
console.log('yield 2', yield 'B');
console.log('generator 3');
};
f = foo();
console.log('tick 1');
console.log(f.next('a'));
console.log('tick 2');
console.log(f.next('b'));
console.log('tick 3');
console.log(f.next('c'));
console.log('tick 4');
console.log(f.next('d'));
This is the log in the terminal:
tick 1
generator 1
{ value: 'A', done: false }
tick 2
yield 1 b
generator 2
{ value: 'B', done: false }
tick 3
yield 2 c
generator 3
{ value: undefined, done: true }
tick 4
{ value: undefined, done: true }
But I can not find the way to easily understand this flow, it is kind of weird. If someone has a simple approach to this problem, please help to explain.
Share Improve this question edited Feb 27, 2018 at 17:02 nem035 35.5k6 gold badges92 silver badges104 bronze badges asked Sep 9, 2016 at 16:32 thelonglqdthelonglqd 1,87219 silver badges30 bronze badges 2- What do you find weird in particular? – Bergi Commented Sep 9, 2016 at 17:10
- The order is perfectly correct and very clear after you learn about how your code forms an AST. – rishat Commented Sep 9, 2016 at 17:15
2 Answers
Reset to default 7Basics
Calling the generator function returns an iterator.
Calling .next()
on an iterator returns an object in the form:
{
value // current value of the iterator,
done // boolean indicating if iteration is finished
}
Calling .next()
on the iterator provided by the generator, runs the code from the current paused point in the generator to the next yield
, pauses the generator on this next yield
and pushes out whatever is the yield
value as the value returned from the .next()
method of the iterator, in the object form shown above.
Anything that you pass into .next()
of this iterator will be returned from the currently paused yield
within the generator.
Since the generator isn't paused on a yield
in the first call to .next()
, anything passed into the first .next()
is is just ignored.
If there are no yield
statements left, whatever the function returns will be the last iterator value.
At this point the done
flag will be set to true
and any further calls to .next()
will return the same value.
Running Example
So, in terms of your code, here's what is happening. I'll ment out each line that happens after an execution step.
Step 1
f = foo();
At this point, the iterator is created and stored in f
but no code in the generator has actually ran. So we have:
function* () {
console.log('generator 1');
console.log('yield 1', yield 'A');
console.log('generator 2');
console.log('yield 2', yield 'B');
console.log('generator 3');
};
Step 2
f.next('a'); // returns { value: 'A', done: false }
This runs the code within the generator up to the first yield
and pushes the yielded 'A'
out of the .next()
call. The 'a'
that is passed into .next()
is just ignored, since its the first call (explained above).
Commenting out the lines that ran leaves us with:
function* () {
// console.log('generator 1');
console.log('yield 1', PAUSE_POINT); // we're paused on the `yield`. Essentially half of this line is done
console.log('generator 2');
console.log('yield 2', yield 'B');
console.log('generator 3');
};
Step 3
f.next('b'); // return { value: 'B', done: false }
This returns 'b'
from the first yield
(the first PAUSE_POINT
) and runs the code to the next yield
, pushing 'B'
out from the iterator.
Removing the lines that run leaves with:
function* () {
// console.log('generator 1');
// console.log('yield 1', 'b'); // this PAUSE_POINT returns 'b'
// console.log('generator 2');
console.log('yield 2', PAUSE_POINT); // no we're paused here
console.log('generator 3');
};
Step 4
f.next('c'); // { value: undefined, done: true }
Which passes 'c'
out of the paused yield
and, since there are no more yields
left, runs to the end of the generator and pushes out whatever the generator returns, which in your case is just an implicit return undefined
. Since we reached the end of the generator function, the done
flag is set to true
.
function* () {
// console.log('generator 1');
// console.log('yield 1', 'b'); // this PAUSE_POINT returns 'b'
// console.log('generator 2');
// console.log('yield 2', 'c'); // this PAUSE_POINT returns 'c'
// console.log('generator 3');
// here we have an implicit return undefined;
};
Step 5 and further on
f.next('d'); // { value: undefined, done: true }
Any calls to .next()
after the generator is finished (i.e. done
is true
) just returns whatever the last value was. Passing 'd'
into this method serves no purpose anymore.
Additional Example
var foo = function* () {
console.log('first call to next runs to yield #1');
var a = yield 'A'; // this yield pushes 'A' and returns 'a'
console.log('second call to next runs to yield #2');
var b = yield 'B'; // this yield pushes 'B' and returns 'b'
console.log('third call to next runs to the end of the generator ');
// there's no return statement here so we are returning undefined
};
var f = foo();
console.log(f.next('this gets ignored')); // { value: 'A', done: false }
console.log(f.next('a')); // { value: 'B', done: false }
console.log(f.next('b')); // { value: undefined, done: true }
// any further call just returns whatever the last returned value was
console.log(f.next('this also gets ignored since we are done')); // { value: undefined, done: true }
Simple explain is that yield
keyword stops executing code, yield
is like breakpoint, next generator call executes code after last breakpoint to next breakpoint ( if any exists ). So generator function is called in parts, check ments in my example code.
var gen=function*(){
//1.start of first call next()
yield "A";//1.here first next() ends
//2.start of second call next();
yield "B";//2.here end second next();
//3.start of third call next()
yield "C";//3.end of third next() call
//NEXT AFTER THIRD. here every next() after third starts
//no code no yield so value is undefined
//here every next() after third ends
}();
console.log(gen.next().value);//A
console.log(gen.next().value);//B
console.log(gen.next().value);//C
console.log(gen.next().value);//undefined
本文标签: ecmascript 6How does a generator function work in JavascriptStack Overflow
版权声明:本文标题:ecmascript 6 - How does a generator function work in Javascript? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744717226a2621477.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论