最近在學習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有什麼優勢^_^