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

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

原始碼地址

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

}}

一步一步SharePoint 2007

一步一步sharepoint 2007之一 安裝sharepoint 呵呵,如何安裝sharepoint,可能這對很多人來說是a piece...

一步一步配置NLB

廢話不說,配置nlb需要準備以下環境 1 至少兩個伺服器,我的是windows server 2008 r2 我的兩個伺服器名分別為nlb3和nlb2,其中nlb3是主,為什麼呢?後面會談到,在配置時通過設定優先順序。 2 nlb3和nlb2已安裝iis服務。 nlb的互動結構圖如下 其中 dc是個派...

一步一步學Linq to sql

一步一步學linq to sql 一 預備知識 一步一步學linq to sql 二 datacontext與實體 一步一步學linq to...