走一步再走一步,揭開co的神秘面紗

2022-08-05 16:27:20 字數 4516 閱讀 9224

原始碼位址

了解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);

}

我覺得可以把onfulfilledonrejected看成是返回的promise的resolvereject

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...