原始碼位址
了解co
的前提是已經知曉generator
是什麼,可以看軟大神的generator 函式的語法,co是tj大神寫的能夠使generator自動執行的函式庫,而我們熟知的koa也用到了它管理非同步流程控制,將非同步任務書寫同步化,爽的飛起,也擺脫了一直以來的**地獄問題。
首先我們根據co的官方文件來稍做改變看下,到底如何使用co,再一步步進行原始碼分析工作(這篇文章分析的co版本是4.6.0
)。
yield 後面常見的可以跟的型別promises
array (parallel execution)
objects (parallel execution)
generator functions (delegation)
promises
let co = require('co')
let gentimeoutfun = (delay) => `)
}, delay)
})}}
let timeout1 = gentimeoutfun(1000)
let timeout2 = gentimeoutfun(200)
co(function * () ).then((res) => )
array
let co = require('co')
let gentimeoutfun = (delay) => `)
}, delay)
})}}
let timeout1 = gentimeoutfun(1000)
let timeout2 = gentimeoutfun(200)
co(function * () ).then((res) => )
objects
let co = require('co')
let gentimeoutfun = (delay) => `)
}, delay)
})}}
let timeout1 = gentimeoutfun(1000)
let timeout2 = gentimeoutfun(200)
co(function * ()
console.log(a) //
return 'end'
}).then((res) => )
generator functions
let co = require('co')
let gentimeoutfun = (delay) => `)
}, delay)
})}}
let timeout1 = gentimeoutfun(1000)
let timeout2 = gentimeoutfun(200)
function * gen ()
co(function * () ).then((res) => )
最後說一下,關於執行傳入的generator函式接收引數的問題
let co = require('co')
co(function * (name) , 'qianlongo')
從co函式的第二個引數開始,便是傳入的generator函式可以接收的實參
你可以把以上**拷貝至本地測試一番看看效果,接下來我們一步步開始分析co的原始碼首先經過上面的例子可以發現,co函式本身接收乙個generator函式,並且co執行後返回的是promise
function co(gen) );
}
在promise的內部,先執行了外部傳入的gen
,執行的結果如果不具備next屬性(且要是乙個函式),就直接返回,並將執行成功**resolve(gen)
,否則得到的是乙個指標物件。
接下來繼續看...
onfulfilled();
/** * @param res
* @return
* @api private
*/function onfulfilled(res) catch (e)
next(ret); // 緊接著執行next,正是它實現了反覆呼叫自己,自動流程控制,注意ret(即上一次gen.next執行後返回的物件)
}/**
* @param err
* @return
* @api private
*/function onrejected(err) catch (e)
next(ret);
}
我覺得可以把onfulfilled
和onrejected
看成是返回的promise的resolve
和reject
。
而onfulfilled
也是將原生的generator生成器的next方法包裝了一遍,大概是為了抓取錯誤吧(看到內部的try catch了嗎)
好,我們看到了co內部將指標移動到了第乙個位置之後,接著執行了內部的next方法,接下來聚焦在該函式上
function next(ret)
聰明的你,是不是已經明白了co是怎麼將非同步流程自動管理起來了但是我對next函式中的topromise函式還有疑問,他到底做了什麼事?使得co(generatorfun)中yield可以支援陣列、物件、generator函式等形式。
一步步來看
function topromise(obj)
首先如果obj不存在,就直接返回,你想啊,co本來就是依賴上一次指標返回的value是promise或者其他,這個時候如果返回
那就沒有必要再給乙個false值轉成promise形式了吧。
接著,如果obj本身就是個promise也是直接返回,用了內部的ispromise函式進行判斷,我們看下他怎麼實現的。
function ispromise(obj)
其實就是判斷了obj的then屬性是不是個函式
再接著,如果是個generator函式或者generator生成器,那就像你自己呼叫co函式一樣,手動傳到co裡面去執行。
isgeneratorfunction
function isgeneratorfunction(obj)
通過obj的constructor屬性去判斷其是否屬於generatorfunction
,最後如果constructor屬性沒判斷出來,再去用isgenerator,判斷obj的原型是不是generator生成器
function isgenerator(obj)
判斷的條件也比較直接,需要符合兩個條件,乙個是obj.next要是乙個函式,乙個是obj.throw要是乙個函式接下來繼續看
如果obj既不是promise,也不是isgeneratorfunction和isgenerator,要是乙個普通的函式,就將該函式包裝成promise的形式,這裡我們主要需要看thunktopromise
function thunktopromise(fn) );
});}
接下來是重頭戲了,co中如果處理yield後面跟乙個陣列呢?主要是arraytopromise函式的作用
function arraytopromise(obj)
還有最後乙個判斷,如果obj是個物件怎麼辦?
function objecttopromise(obj)
// 最後 使用到了promise.all,將obj中多個promise例項
return promise.all(promises).then(function () );
function defer(promise, key) ));
}}
走一步,再走一步
時光如梭,匆匆流逝的所有,讓我再一次懂得了,人生的時光門票,在不斷的穿梭過去和未來,也任光陰的手撫摸著這個現在,有太多的好像,早已和我的過去劃開了界限,無論悲傷的過往,還是美好而快樂過的曾經,都好像已經不重要了。重要的是,走一步,再走一步。這場在歲月裡一直奔跑的故事,和那始終無法為自己畫上成功圓滿的...
一步一步向前走
一直以來都沒有開始寫部落格,最近開始轉技術方向,所以想記錄下後面的心路歷程。其實,也不算是轉技術方向,因為,這個方向也屬於自己職業規劃的一部分。本人本科學歷,電子資訊工程專業,目前從事應用軟體開發工作,現打算轉向驅動及linux核心開發。未踏足社會時,就想著自己應該成為乙個,能從無到有開發並推出產品...
一步一步走 之 TCP IP初試水
tcp ip協議,我們平時說得很多,聽得很多,但大多數人只是知道有這麼乙個東西,而並不知道這個東西是什麼樣的,是幹什麼的,當然,我也不知道,正因為不知道,所以就得去學習,這才是真正的學習之道,被動的學習永遠不能帶給你什麼。而我此次重點介紹tcp udp ip協議 tcp transmission c...