最近在學習redux-saga,由於redux-saga需要使用Generator函式,所以下來就回顧了一下Generator
Generator 函式是 ES6 提供的一種非同步程式設計解決方案,語法行為與傳統函式完全不同
寫法上Generator函式與普通函式沒什麼區別,只是在function
關鍵字後面多了一個*
號,函式內部多了一個yield
關鍵字
function* demo() {
console.log(1)
yield 111
console.log(2)
yield 222
console.log(3)
return 333
}
上面的函式即為一個Generator函式,Generator呼叫後並不會直接執行,而是返回一個指向內部狀態的指標物件需要呼叫該指標物件的next
方法才會向下執行,當遇到yield
關鍵字的時候,函式會掛起,交給外部,直到遇到下一次呼叫next
方法
let g = demo()
此時若我們第一次呼叫
let val1 = g.next()
// 列印 1,val1 = {value: 111, done: false}
let val2 = g.next()
// 列印 2,val2 = {value: 222, done: false}
let val3 = g.next()
// 列印 3,val3 = {value: 333, done: true}
根據結果我們可以很清楚的看到當返回值的done
為true
的時候就代表Generator執行完畢,此外Generator函式還可以被迴圈
for (let val of demo()) {
console.log(val)
}
// val依次會列印出 111、222,注意當done為true的時候不會列印value的值
當然Generator在工作中最常用到的就是處理非同步函式,下面舉個例子:
function demo(a, b) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(a + b)
}, 1000)
})
}
function* gen(val) {
let a = yield demo(1, 2)
console.log(a)
let b = yield '123'
return b
}
這裡需要注意的是,變數a
的值是需要next
方法傳入的
let g = gen()
let {value} = g.next()
此時函式中的變數a的值就是再次呼叫next
傳入的值, 比如g.next(value)
,則此時a的值就是一個Promise的例項,顯然這不是我們想要的,我們期望拿到的是Promise.resolve
的值
那麼根據上面的結果我們可以編寫一個Generator執行器
function execGen(gen) {
let g = gen()
function deep(val) {
let {value, done} = g.next(val)
if (done) {
return
}
if (value instanceof Promise) {
value.then(data => {
deep(data)
})
} else {
deep(value)
}
}
deep()
}
execGen(gen)
// gen函式的console會正確的列印出值3
其實如果不是redux-saga的話我感覺我工作中基本不會用到Generator函式,個人感覺更優雅的是async/await 來處理非同步情況
async function handler() {
try{
let val = await demo()
}catch (e) {
}
}
最後還是期望有大佬能夠幫忙指出相比於async/await,Generator有什麼優勢^_^