co.js是基於es6的generator實現的,相當於generator函數的一個自動執行器
generator的簡單介紹
function* fn(){ before() yield firstYield() yield secYield() end() } let gen = fn()//生成構造器 gen.next()//執行到第一個yield的位置,即只執行before(),firstYield() gen.next()//執行到第二個yield的位置,只執行secYield() gen.next()//執行直到結束,執行end()
co.js的實現
將一個異步函數thunk化
原函數
fs.readFile(path,callback)
thunk化后函數
let readFile = (path) => (callback) => fs.readFile(path, callback)
將readFile的異步執行generator函數傳入co
co(function* (){ let data1 = yield readFile('path1') console.log(data1)//顯示path1的文件的內容 let data2 = yield readFile('path2') console.log(data2)//顯示path2的文件內容 })
分析 co 函數
let co = (fn) => { let gen = fn()//將gen指向generator構造器 let next = (err, data) => { /**next函數,作用1.將上一步回調函數中data穿會給gen時期能為其他變量賦值,作用2:將gen向下一步運行,作用3.將next函數當成回調函數傳給gen的某一步,使其將data傳回next並執行下一步**/ let result = gen.next(data) if(! result.done){ result.value(next) } } next() }
分析執行過程
1.co(……)
執行let gen = fn (相當於gen =function* (){
let data1 = yield readFile('path1') console.log(data1)//顯示path1的文件的內容 let data2 = yield readFile('path2') console.log(data2)//顯示path2的文件內容 })
2.next()
執行let result = gen.next() (
相當於 let result = {done: false, value: readFile('path1')} (
相當於 let result = { done: false, value: (callback) => fs.readFile(‘path1’, callback)}
)
)
執行 if(! result.done ) //true||false
執行 result.value(next) (
相當於 ((callback) => fs.readFile('path1',callback))(next) (
相當於 fs.readFile('path1', next)
)
)
3. 當文件讀取完畢之后,調用 fs.readFile()執行回調函數next(err,data)返回第二步
4.執行完畢,執行完generator函數的所有步驟