读书笔记-es6Generator函数
2017.05.08
hzzly
Generator函数
从语法上,可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态。 调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象(遍历器对象)。 Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。 Generator 函数也不能跟new命令一起用,会报错。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function * helloWorldGenerator ( ) { yield 'hello' ; yield 'world' ; return 'ending' ; } var hw = helloWorldGenerator ();hw.next () hw.next () hw.next () hw.next ()
总结一下,调用 Generator 函数,返回一个遍历器对象,代表 Generator 函数的内部指针。以后,每次调用遍历器对象的next方法,就会返回一个有着value和done两个属性的对象。value属性表示当前的内部状态的值,是yield表达式后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束。
写法
1 2 3 4 function * foo (x, y ) { ··· }function *foo (x, y ) { ··· }function * foo (x, y ) { ··· }function *foo (x, y ) { ··· }
一、yield 表达式
由于 Generator 函数返回的遍历器对象,只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield表达式就是暂停标志。
遍历器对象的next方法的运行逻辑如下: 1)遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。 2)下一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式。 3)如果没有再遇到新的yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。 4)如果该函数没有return语句,则返回的对象的value属性值为undefined。
1 2 3 4 5 6 function * gen ( ) { yield 123 + 456 ; } var g = gen ()gen.next ()
二、for…of 循环
for…of循环可以自动遍历 Generator 函数时生成的Iterator对象,且此时不再需要调用next方法。
1 2 3 4 5 6 7 8 9 10 11 12 function *foo ( ) { yield 1 ; yield 2 ; yield 3 ; yield 4 ; yield 5 ; return 6 ; } for (let v of foo ()) { console .log (v); }
这里需要注意,一旦next方法的返回对象的done属性为true,for…of循环就会中止,且不包含该返回对象,所以上面代码的return语句返回的6,不包括在for…of循环之中。
除了for…of循环以外,扩展运算符(…)、解构赋值和Array.from方法内部调用的,都是遍历器接口。这意味着,它们都可以将 Generator 函数返回的 Iterator 对象,作为参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function * numbers () { yield 1 yield 2 return 3 yield 4 } [...numbers ()] Array .from (numbers ()) let [x, y] = numbers ();x y for (let n of numbers ()) { console .log (n) }
三、作为对象属性的Generator函数 1 2 3 4 5 6 7 8 9 10 11 let obj = { * myGeneratorMethod ( ) { ··· } }; let obj = { myGeneratorMethod : function * () { } };
四、应用
1)异步操作的同步化表达
1 2 3 4 5 6 7 8 9 10 function * loadUI ( ) { showLoadingScreen (); yield loadUIDataAsynchronously (); hideLoadingScreen (); } var loader = loadUI ();loader.next () loader.next ()
1 2 3 4 5 6 7 8 9 10 11 12 function * main ( ) { var result = yield request ("http://some.url" ); var resp = JSON .parse (result); console .log (resp.value ); } function request (url ) { makeAjaxCall (url, function (response ){ it.next (response); }); } var it = main ();it.next ();
2)控制流管理
1 2 3 4 5 6 7 8 9 step1 (function (value1 ) { step2 (value1, function (value2 ) { step3 (value2, function (value3 ) { step4 (value3, function (value4 ) { }); }); }); });
采用 Promise 改写上面的代码。
1 2 3 4 5 6 7 8 9 10 Promise .resolve (step1) .then (step2) .then (step3) .then (step4) .then (function (value4 ) { }, function (error ) { }) .done ();
Generator 函数可以进一步改善代码运行流程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function * longRunningTask (value1 ) { try { var value2 = yield step1 (value1); var value3 = yield step2 (value2); var value4 = yield step3 (value3); var value5 = yield step4 (value4); } catch (e) { } } scheduler (longRunningTask (initialValue));function scheduler (task ) { var taskObj = task.next (task.value ); if (!taskObj.done ) { task.value = taskObj.value scheduler (task); } }