生成器
生成器是 ECMAScript 6 新增的一個極為靈活的結構,擁有在一個函數塊內暫停和恢復代碼執行的能力。
生成器基礎
生成器的形式是一個函數,函數名稱前面加一個星號表示它是一個生成器。?
//生成器函數聲明 function* generatorFn(){} //生成器函數表達式 let generatorFn = function* () {} //作為對象字面量方法的生成器函數 let generator = { * generatorFn() {} } //作為類實例方法的生成器函數 class generator { * generatorFn() {} } //最為類靜態方法的生成器函數 class generator { static * generatorFn() {} } //箭頭函數不能用來定義生成器函數
生成器也具有next()方法,有一個done屬性和一個value屬性。
函數體為空的生成器函數中間不會停留,調用一次next()就會讓生成器到達done:true狀態。
function* generatorFn() {} let generatorObject = generatorFn(); console.log(generatorObject); // generatorFn {<suspended>} console.log(generatorObject.next()); // { done: true, value: undefined }
value屬性是生成器的返回值,默認為undefined,可以通過生成器函數的返回值指定
function* generatorFn(){ return 'foo'; } let generatorObject = generatorFn(); console.log(generatorObject); // generatorFn {<suspended>} console.log(generatorObject.next()); // { done: true, value: 'foo' }
?生成器的中斷與執行
yield關鍵字可以讓生成器停止和開始執行。停止執行的生成器函數只能通過在生成器對象上調用next()方法來恢復執行。
function* generatorFn() { yield; } let generatorObject = generatorFn(); console.log(generatorObject.next()); // { done: false, value: undefined } console.log(generatorObject.next()); // { done: true, value: undefined }
yield和return類似,但是yield關鍵字退出的生成器函數會處在done:false狀態,return是true狀態。
function* generatorFn() { yield 'foo'; yield 'bar'; return 'baz'; } let generatorObject = generatorFn(); console.log(generatorObject.next()); // { done: false, value: 'foo' } console.log(generatorObject.next()); // { done: false, value: 'bar' } console.log(generatorObject.next()); // { done: true, value: 'baz' }
throw()和return()方法都可以用于強制生成器進入關閉狀態。
function* generatorFn() {} const g = generatorFn(); console.log(g); // generatorFn {<suspended>} console.log(g.next); // f next() { [native code] } console.log(g.return); // f return() { [native code] } console.log(g.throw); // f throw() { [native code] }
return()方法會強制生成器進入關閉狀態。提供給return方法的值就是終止迭代器對象的值
function* generatorFn() { for (const x of [1, 2, 3]) { yield x; } } const g = generatorFn(); console.log(g); // generatorFn {<suspended>} console.log(g.return(4)); // { done: true, value: 4 } console.log(g); // generatorFn {<closed>}
throw()方法會在暫停的時候將一個提供的錯誤注入到生成器對象中。如果錯誤未被處理,生成器就會關閉
function* generatorFn() { for (const x of [1, 2, 3]) { yield x; } } const g = generatorFn(); console.log(g); // generatorFn {<suspended>} try { g.throw('foo'); } catch (e) { console.log(e); // foo } console.log(g); // generatorFn {<closed>}
如果生成器函數內部處理了這個錯誤,那么生成器就不會關閉,還可以恢復執行。錯誤處理會跳過對應的yield。
function* generatorFn() { for (const x of [1, 2, 3]) { try { yield x; } catch(e) {} } } const g = generatorFn(); console.log(g.next()); // { done: false, value: 1} g.throw('foo'); console.log(g.next()); // { done: false, value: 3}
如果生成器對象還沒有開始執行,那么調用 throw()拋出的錯誤不會在函數內部被捕獲,因為這相當于在函數塊外部拋出了錯誤。