TypeScript 生成器(Generator)
迭代器和生成器這兩個概念總是很容易混淆,經過上節的學習我們知道迭代器是一個對象,那么本節首先要記?。?strong>生成器是一種能夠中途停止,然后從停止的地方繼續運行的函數。可以借助 yield
或 return
停止函數運行。
1. 慕課解釋
通過 function*
來創建一個生成器函數,在調用一個生成器函數后,并不會立即執行函數中的代碼,而是會返回一個迭代器對象,通過調用迭代器對象的 next()
方法,可以獲得 yield/return
的返回值。
2. 生成器函數的特殊性
一個正常的函數,如果沒有 return
或者 throw
一個異常,一旦被調用在運行結束之前是不會停止的。如果再次調用這個函數,它會再次從第一行開始執行。
function normalFunc() {
console.log('I')
console.log('cannot')
console.log('be')
console.log('stopped.')
}
In contrast, a generator is a function that can stop midway and then continue from where it stopped.
相反,生成器函數可以中途停止,然后從停止的地方繼續執行的。
生成器函數會返回一個對象,可以調用這個對象上的 next()
方法。
3. 示例代碼
function* generatorFunction() {
console.log('開始執行')
yield 'Hello, '
console.log('暫停后再次執行')
yield 'World!'
}
let iterator = generatorFunction()
此時,通過 function*
語法創建了一個生成器函數,調用這個函數并賦值給變量 iterator
,我們已經知道這是個對象。
console.log(iterator.next().value)
// 開始執行
// Hello,
調用 iterator 對象上的 next()
方法,首先打印出 開始執行
,然后遇到了 yield Hello,
,yield
會將后面的值返回,生成器生成一個對象 { value: 'Hello, ', done: false }
,函數停止運行,直到再次調用 next()
方法。
console.log(iterator.next().value)
// 暫停后再次執行
// World!
再次調用 next()
方法,函數內繼續執行,打印出 暫停后再次執行
,遇到 yield 'World!'
,生成對象 { value: 'World!', done: false }
,函數停止運行,直到再次調用 next()
方法。
console.log(iterator.next())
再次調用 next()
方法,這次函數內沒有返回值,也就是默認返回 undefined
, 生成對象 { value: 'undefined', done: true }
。
4. 通過 next() 參數向生成器傳值
在調用 next() 的時候可以傳遞一個參數,在上次 yield 前接收到這個參數:
function* gen() {
console.log('開始執行')
let res1 = yield 1
console.log('中斷后繼續執行')
console.log(res1)
let res2 = yield 2
console.log(res2)
console.log('執行結束')
return 3
}
let iterator = gen()
console.log(iterator.next('first'))
console.log(iterator.next('second'))
console.log(iterator.next('third'))
執行并查看結果:
開始執行
{ value: 1, done: false }
中斷后繼續執行
second
{ value: 2, done: false }
third
執行結束
{ value: 3, done: true }
這里注意下,生成器最初沒有產生任何結果,在第一次調用 next()
時傳參是無意義的。
5. 小結
生成器還有另一個巨大的好處,就是把異步回調代碼變成“同步”代碼。async await
就是基于生成器函數的語法糖,await
可以等待異步函數執行完畢再繼續執行后面的代碼。