生成器是由生成器函數( generator function )運行後獲得的,是可迭代的。ajax
function* gen() { yield 'a'; yield 'b'; yield 'c'; } let g = gen(); // "Generator { }"
生成器有一個很大的特色,它能夠暫停內部代碼運行,返回一個值給外部函數。(暫停後不會阻止其餘代碼運行)當外部調用其 next 方法後,會繼續執行剩下的代碼,並接受外部傳來的一個參數。這個實現主要依賴於關鍵字 yield 。dom
yield 關鍵字使生成器函數執行暫停, yield 關鍵字後面的表達式的值返回給生成器的調用者。它能夠被認爲是一個基於生成器的版本的 return 關鍵字。
function* g(){ var a = yield 2; console.log(a); } var it = g(); // 返回一個可迭代的生成器對象 console.log(it.next()); // 執行生成器函數內部代碼,第一次返回 {done: false, value: 2} it.next(3); // 繼續執行生成器函數內部代碼,同時向生成器傳遞參數3,最後返回 {done: true, value: undefined}
一個簡單的計數器異步
function* count(){ var n = 1; while(true){ yield n++; } } var it = count(); it.next(); // 1 it.next(); // 2 it.next(); // 3
之前處理異步 ajax 請求結果,通常採用傳遞迴調函數的方式。一旦遇到多層回調嵌套,代碼的可讀性會下降,而且調試起來也不方便。有了生成器以後,咱們就能夠用同步的方式寫異步的代碼。這聽上去很是的有意思。咱們的代碼將會是這樣的async
function foo(){ var result = asyncFun(); // asyncFun 是異步函數,result 是異步返回的結果 console.log(result); }
固然,上面的代碼並不能獲得正確的結果,它只是一個設想。咱們正打算用生成器來實現,並且這是可行的。想一想生成器有哪些特色:函數
這就足夠了。有了生成器函數,如今咱們從新來設計代碼:設計
function* foo(){ // 這裏遇到了異步方法,必須停下來。 // 等待異步方法執行完畢,並返回結果,繼續運行代碼。固然,同步 ajax 不能算,它不是異步 // 輸出結果 }
靜下來想想有哪些關鍵字,與暫停、繼續有關。停下來...繼續...停下來...繼續...停下來...繼續...Don't...Stop...Don't...Stop...Don't...Stop......這兩個詞就是 yield、next.調試
function *foo(){ var result = yield asyncFun(next); console.log(result); }
當代碼遇到 yield 會暫停,這個時候 asyncFun 函數是不會暫停的,會執行,等執行完畢,再調用生成器的 next 方法,並將返回結果做爲參數傳給 next。因爲在生成器函數內部咱們拿不到 next,必須藉助於全局變量來傳遞 next。code
var next, gn; function asyncFun(next){ // 模擬異步請求 setTimeout(function(){ // 返回一個隨機數 next(Math.random()) }, 1000) } function* foo(){ var result = yield asyncFun(next); console.log(result); } gn = foo(); next = gn.next.bind(gn); next(); // 打印隨機數
這樣寫,運行看上去有些繁重。能夠寫一個包裝函數運行含有異步代碼的生成器函數。對象
function asyncFun(next){ // 模擬異步請求 setTimeout(function(){ // 返回一個隨機數 next(Math.random()) }, 1000) } function* foo(){ var result = yield function(next){asyncFun(next)}; console.log(result); } function wrapFun (gFn){ var gn = foo(), next = gn.next.bind(gn); next().value(next); } wrapFun(foo);
演示地址get
不過,自從出了 Promise 和 await 以後,更多的是用這個組合,其使用也更簡單,範圍也更廣。