js generator是一个状态机
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| function* foo() { a++; yield; b = b * a; a = (yield b) + 3; }
function* bar() { b--; yield; a = (yield 8) + b; b = a * (yield 2); }
function step(gen) { let it = gen(); let last; return function () { last = it.next(last).value; } }
let a = 1; let
|
js generator是一个状态机
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| function* foo() { a++; yield; b = b * a; a = (yield b) + 3; }
function* bar() { b--; yield; a = (yield 8) + b; b = a * (yield 2); }
function step(gen) { let it = gen(); let last; return function () { last = it.next(last).value; } }
let a = 1; let b = 2; let s1 = step(foo); let s2 = step(bar); s2(); s2(); s1(); s2(); s1(); s1(); s2(); console.log(a, b);
|
这段代码在最后一个s2的时候会出现一个问题,按照一般的想法,前一个s1()已经把a变为12了,最后这个s2执行
应该是b=12*2
但最后输出的是12,18,并不是12,24。
//原因就在于生成器是一个状态机,yield是状态的分界线,next是切换到下一个状态。
这段bar()中的代码左边是b=a*,
因为js默认顺序是ltr(left to right),并且生成器需要保持上下文状态,所以这句话在执行的时候
先来获取a的值,就是9,然后yield暂停并保持a的值的状态。然后再执行两个s1()虽然改变了a的值,但是由于s2()状态机保持了状态所以导致s2()中的a的值还是9。
//由于yield左边运算是上一个状态,也就是说上一个状态a=9,然后再是b=9*2,所以b=18
如果把代码换成
那就会输出12,24了
因为ltr,所以先通过yield暂停了,没有先获取a的值所以没有保持a的值,导致两个s1()执行完毕后执行s2()之后a要重新获取
//因为yield右边不是上一个状态,而是下一个状态,所以a从全局变量a获取就是12,然后再是2*12=24
//所以输出12,24
整个完整的运行步骤
1 2 3 4 5 6 7 8 9 10
| s2的状态 a=1,b=1,barlast=undefined s2的状态 a=1,b=1,barlast=8 s1的状态 a=2,b=1,foolast=undefined s2的状态 a=9,b=1,barlast=2 s1的状态 a=9,b=9,foolast=9 s1的状态 a=12,b=9,foolast=done s2的状态 //(注意这里s2() yield左边运算是上一个状态,也就是说上一个状态a=9,然后再是b=9*2) 所以此时 a=12,b=18,barlast=done
|