摘要:昨天也是好好的看了一下的源碼,今天打算自己來做一下解析。源碼如下這段代碼真的是很短,但是方法真的很巧妙。因?yàn)閮蓚€(gè)方法用到了,這里把的源碼也貼出來源碼的描述就是為了執(zhí)行而創(chuàng)建的。最后再次感謝提供的思路。
原文鏈接,轉(zhuǎn)載請注明出處
最近看了Ma63d關(guān)于爬蟲的這篇文章,正好自己也在做爬蟲,看到他在文中提到了co-parallel和co-gather,就打算改一下自己的代碼(本來代碼就只是為了爬一些自己感興趣的東西,現(xiàn)在還在改,地址在這里)。昨天也是好好的看了一下co-parallel的源碼,今天打算自己來做一下解析。
co-parallel源碼如下:
var thread = require("co-thread"); module.exports = function *parallel(thunks, n){ var n = Math.min(n || 5, thunks.length); var ret = []; var index = 0; function *next() { var i = index++; ret[i] = yield thunks[i]; if (index < thunks.length) yield next; } yield thread(next, n); return ret; };
這段代碼真的是很短,但是方法真的很巧妙。因?yàn)閮蓚€(gè)方法用到了co-thread,這里把co-thread的源碼也貼出來:
function thread(fn, n) { var gens = []; while (n--) gens.push(fn); return gens; }
Run fn n times in parallel.
源碼的描述就是為了parallel執(zhí)行而創(chuàng)建的。由于在next外部創(chuàng)建了一個(gè)index變量,通過控制index的變化就可以使得每次執(zhí)行的next函數(shù)都是不同的函數(shù),在next中繼續(xù)遞歸yield自己的話就是可以繼續(xù)執(zhí)行不同的next,最終把所有的thunks都yield了一遍,方法是不是很巧妙。
如果你覺得我說的話很混亂,那我們還是還是拿一個(gè)co-parallel中的例子來講吧
var request = require("co-request"); var co = require("co"); var parallel = require("co-parallel"); var urls = [ "http://google.com", "http://yahoo.com", "http://ign.com", "http://cloudup.com", "http://myspace.com", "http://facebook.com", "http://cuteoverload.com", "http://uglyoverload.com", "http://segment.io" ]; function *status(url) { console.log("GET %s", url); var s = (yield request(url)).statusCode; return s; } co(function *(){ var start = Date.now(); var reqs = urls.map(status); var res = yield parallel(reqs, 3); console.log(res); console.log("duration: %dms", Date.now() - start); });
直接看到var reqs = urls.map(status);這句,由于傳遞給map的callback是一個(gè)Generator函數(shù),所以最后的返回就是Generator的內(nèi)部指針,也就是Iterator,也就是status()執(zhí)行了一遍返回的結(jié)果。
再到var res = yield parallel(reqs, 3);這里,由于parallel是一個(gè)Generator,所以直接進(jìn)入parallel中,因?yàn)?b>n=3所以thread返回的數(shù)組內(nèi)容應(yīng)該是類似這個(gè) [function*() {yield thunks[0]},function*(){yield thunks[1]}]。由于yield thread返回的結(jié)果是數(shù)組,在co中會對數(shù)組做Promise.all(obj.map(toPromise, this));因?yàn)閛bj中都是Generator,所以toPromise會直接對每一個(gè)Generator繼續(xù)調(diào)用co(function*(){yield thunk[i]})。在next中最后又繼續(xù)yield自己,所以當(dāng)當(dāng)一個(gè)thunk結(jié)束之后會繼續(xù)下一個(gè)thunk。
co-gatherco-gather實(shí)現(xiàn)的和co-parallel差不多的功能,只是增加了并行錯(cuò)誤處理機(jī)制。因?yàn)?b>Promise.all方法會在其中任何一個(gè)出問題的時(shí)候都把錯(cuò)誤扔出來, co-gather是對all中每一個(gè)方法都做了錯(cuò)誤處理,讓Promise.all方法不會拋錯(cuò),源碼如下:
var thread = require("co-thread"); module.exports = function *gather(thunks, n){ n = Math.min(n || 5, thunks.length); var ret = []; var index = 0; function *next() { var i = index++; ret[i] = {isError: false}; try { ret[i].value = yield thunks[i]; } catch (err) { ret[i].error = err; ret[i].isError = true; } if (index < thunks.length) yield next; } yield thread(next, n); return ret; };
和co-parallel不同的地方就在于對yield thunks[i]做了一層try catch,然后返回的包含執(zhí)行結(jié)果的對象。
總結(jié)單單是看parallel的代碼還是很好理解的,但是由于自己co的源碼理解的不好,所以自己在捋清e(cuò)xample的時(shí)候有點(diǎn)混亂了,后來又重新仔細(xì)的看了一遍了co的源碼以及阮一峰的Generator的講解,自己才弄明白。最后再次感謝Ma63d提供的思路。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/86707.html
承繼上篇內(nèi)容:下面是parseHTML 函數(shù)源碼解析 varstartTagMatch=parseStartTag(); if(startTagMatch){ handleStartTag(startTagMatch); if(shouldIgnoreFirstNewline(startTagMatch.tagName,html)){ advance(1); } co...
這是講 ahooks 源碼的第一篇文章,簡要就是以下幾點(diǎn): 加深對 React hooks 的理解?! W(xué)習(xí)如何抽象自定義 hooks。構(gòu)建屬于自己的 React hooks 工具庫?! ∨囵B(yǎng)閱讀學(xué)習(xí)源碼的習(xí)慣,工具庫是一個(gè)對源碼閱讀不錯(cuò)的選擇。 注:本系列對 ahooks 的源碼解析是基于v3.3.13。自己 folk 了一份源碼,主要是對源碼做了一些解讀,可見詳情?! 〉谝黄饕榻B a...
vue parseHTML函數(shù)解析器遇到結(jié)束標(biāo)簽,在之前文章中已講述完畢。 例如有html(template)字符串: <divid="app"> <p>{{message}}</p> </div> 產(chǎn)出如下: { attrs:["id="app"","id...
現(xiàn)在我們講compileToFunctions 的使用方法,現(xiàn)在看看內(nèi)容: //compile varcompiled=compile(template,options); 其實(shí)真正應(yīng)該講的就是 compile 函數(shù)?! 〗馕?compile 上述代碼在調(diào)用 compile ,其中模板字符串 template ,就是讓選項(xiàng)參數(shù) options 的第二個(gè)參數(shù)傳遞給 compile 函數(shù)...
摘要:前言源碼解析一模版渲染源碼解析二雙向綁定官網(wǎng)給出的如下結(jié)果源碼分析判斷參數(shù)是否包含屬性本例中本例中和是函數(shù)監(jiān)聽計(jì)算屬性設(shè)置,延遲執(zhí)行的方法設(shè)置可以通過本例方式訪問計(jì)算屬性對象初始化時(shí)會針對屬性的所有值分別一個(gè)對象,在源碼解析二中有詳細(xì)介 前言 1、Vue源碼解析(一)-模版渲染2、Vue源碼解析(二)-MVVM雙向綁定 demo 官網(wǎng)給出的demo如下 new Vue({ el...
閱讀 3005·2021-10-13 09:39
閱讀 2702·2021-09-27 13:34
閱讀 2041·2019-08-30 15:55
閱讀 3268·2019-08-30 15:43
閱讀 3647·2019-08-30 11:16
閱讀 1762·2019-08-26 18:28
閱讀 1298·2019-08-26 13:56
閱讀 924·2019-08-26 13:35