本文實例講述了JS co 函數(shù)庫的含義和用法。分享給大家供大家參考,具體如下:
網(wǎng)站建設(shè)公司,為您提供網(wǎng)站建設(shè),網(wǎng)站制作,網(wǎng)頁設(shè)計及定制網(wǎng)站建設(shè)服務(wù),專注于成都定制網(wǎng)站,高端網(wǎng)頁制作,對成都主動防護(hù)網(wǎng)等多個行業(yè)擁有豐富的網(wǎng)站建設(shè)經(jīng)驗的網(wǎng)站建設(shè)公司。專業(yè)網(wǎng)站設(shè)計,網(wǎng)站優(yōu)化推廣哪家好,專業(yè)成都網(wǎng)站營銷優(yōu)化,H5建站,響應(yīng)式網(wǎng)站。
繼續(xù)學(xué)習(xí)阮一峰老師異步編程四部曲之三:co
co在很早之前就聽超哥講過,說在node編程中大量用到,源碼很簡單,但是想法很強大。
讓我有空抓緊了解下,前一段時間弄離職的事情,跑來跑去累的夠嗆。
現(xiàn)在終于一切回歸正常了,還在拼命的適應(yīng)新公司的節(jié)奏。只能趁周末繼續(xù)學(xué)習(xí)了。
好了,不瞎扯了,回歸主題,前兩篇文章我們分別學(xué)習(xí)了 Generator 函數(shù)和 Thunk 方式的自動執(zhí)行。
今天我們接著上次的思路學(xué)習(xí)使用 co 工具實現(xiàn) Generator 函數(shù)的自動執(zhí)行。
再次拿出上一節(jié)的示例:
var fs = require('fs'); var thunkify = require('thunkify'); var readFile = thunkify(fs.readFile); var gen = function* (){ var r1 = yield readFile('/etc/fstab'); console.log(r1.toString()); var r2 = yield readFile('/etc/shells'); console.log(r2.toString()); };
這段代碼用于讀取兩個文件,怎么使用 co 工具來實現(xiàn)自動執(zhí)行呢?
很簡單:
var co = require('co'); co(gen);
上面代碼中,只要把 Generator 函數(shù)傳入 co 函數(shù),就會自動執(zhí)行。
co 函數(shù)返回一個 Promise 對象,因此可以用 then 方法添加回調(diào)函數(shù),當(dāng) Generator 執(zhí)行結(jié)束就會觸發(fā)回調(diào):
co(gen).then(function (){ //success });
這么看起來的話好像和我們之前的 Thunk 方式差不多啊,只是把 run 函數(shù)名改成了 co
唯一的區(qū)別是多了一層 Promise 包裝,那么 co 和 Thunk 到底有什么區(qū)別呢?
正如我們的猜測一樣,co 其實是將之前的兩種自動執(zhí)行方式(Thunk 和 Promise)結(jié)合到了一起,包裝成一個庫。
使用它的前提和比Thunk多了一種 Promise 的情況,也就是yield返回值必須是 Thunk 函數(shù)和 Promise 對象之一
實現(xiàn)原理:
之前我們在研究 Thunk 函數(shù)時的第一步是使用 thunkify 將 readFile 包裝成 Thunk 函數(shù):
今天我們研究 Promise 就需要把 readFile 包裝成 Promise 對象,看代碼:
var fs = require('fs'); var readFile = function (fileName){ return new Promise(function (resolve, reject){ fs.readFile(fileName, function(error, data){ if (error) reject(error); resolve(data); }); }); }; var gen = function* (){ var f1 = yield readFile('/etc/fstab'); var f2 = yield readFile('/etc/shells'); console.log(f1.toString()); console.log(f2.toString()); };
接下來是我特別喜歡老師做的一件事,先用最原始的方式,手動執(zhí)行一遍代碼。
在我們?nèi)粘i_發(fā)的過程中,也可以參考這種方式。當(dāng)邏輯復(fù)雜時,不妨先用最直白的方式把它實現(xiàn),
然后再去發(fā)現(xiàn)里面的規(guī)則,去優(yōu)化重構(gòu)。又開始扯了,看一下手動執(zhí)行的代碼:
var g = gen(); g.next().value.then(function(data){ g.next(data).value.then(function(data){ g.next(data); }); });
手動執(zhí)行其實就是用 then 方法,層層添加回調(diào)函數(shù)。理解了這一點,就可以寫出一個自動執(zhí)行器:
function run(gen){ var g = gen(); //開始執(zhí)行 function next(data){ var result = g.next(data); if (result.done) return result.value; result.value.then(function(data){ next(data); }); } next(); } run(gen);
和Thunk函數(shù)的區(qū)別是,Thunk 函數(shù)在執(zhí)行成功后把 next 傳給 thunkify ,讓 thunkify 來幫忙執(zhí)行 next
這里的做法是吧 next 交給 Promise,promise 控制請求成功時執(zhí)行 next。區(qū)別只有這么一點。
分析了原理之后,我們來分析下co的源碼:
co 函數(shù)接受一個 Generator 參數(shù),返回一個 Promise 對象
function co(gen) { var ctx = this; return new Promise(function(resolve, reject) { }); }
在返回的 Promise 對象里面,先檢查參數(shù) gen 是否為 Generator 函數(shù)。如果是,就執(zhí)行該函數(shù),得到一個內(nèi)部指針對象;
如果不是就返回,并將 Promise 對象的狀態(tài)改為 resolved 。
function co(gen) { var ctx = this; return new Promise(function(resolve, reject) { if (typeof gen === 'function') gen = gen.call(ctx); if (!gen || typeof gen.next !== 'function') return resolve(gen); }); }
接著,co 對 next 方法進(jìn)行包裝,使異常能夠暴露出來:
function co(gen) { var ctx = this; return new Promise(function(resolve, reject) { if (typeof gen === 'function') gen = gen.call(ctx); if (!gen || typeof gen.next !== 'function') return resolve(gen); onFulfilled(); function onFulfilled(res) { var ret; try { ret = gen.next(res); } catch (e) { return reject(e); } next(ret); } }); }
最后就是next方法了:
function next(ret) { if (ret.done) return resolve(ret.value); var value = toPromise.call(ctx, ret.value); if (value && isPromise(value)) return value.then(onFulfilled, onRejected); return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, ' + 'but the following object was passed: "' + String(ret.value) + '"')); } });
next方法最主要的一行:
if (value && isPromise(value)) return value.then(onFulfilled, onRejected);
co的使用條件,每一次yield返回必須是Promise對象,當(dāng)promist處理成功時再次執(zhí)行onFulfilled
以此來達(dá)到自動執(zhí)行的效果。
co 還支持并發(fā)的異步操作,yield 返回一個數(shù)組或者是支持遍歷的對象即可:
// 數(shù)組的寫法 co(function* () { var res = yield [ Promise.resolve(1), Promise.resolve(2) ]; console.log(res); }).catch(onerror); // 對象的寫法 co(function* () { var res = yield { 1: Promise.resolve(1), 2: Promise.resolve(2), }; console.log(res); }).catch(onerror);
至此,co 的自動執(zhí)行原理我們已經(jīng)學(xué)習(xí)完成了,
其實本質(zhì)上不是很難,只是涉及到的模塊較多,思路比較靈活
對我的小容量大腦來說,現(xiàn)在的認(rèn)識還只到90%
所以這篇文章里面自己的思想比較少,更多的還是在復(fù)述老師的思路。
最后貼上原文的地址:co 函數(shù)庫的含義和用法
感興趣的朋友可以使用在線HTML/CSS/JavaScript代碼運行工具:http://tools.jb51.net/code/HtmlJsRun測試上述代碼運行效果。
更多關(guān)于JavaScript相關(guān)內(nèi)容可查看本站專題:《JavaScript常用函數(shù)技巧匯總》、《javascript面向?qū)ο笕腴T教程》、《JavaScript錯誤與調(diào)試技巧總結(jié)》、《JavaScript數(shù)據(jù)結(jié)構(gòu)與算法技巧總結(jié)》及《JavaScript數(shù)學(xué)運算用法總結(jié)》
希望本文所述對大家JavaScript程序設(shè)計有所幫助。
當(dāng)前題目:JSco函數(shù)庫的含義和用法實例總結(jié)
分享地址:http://vcdvsql.cn/article34/gjeppe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供建站公司、網(wǎng)站改版、自適應(yīng)網(wǎng)站、網(wǎng)站制作、ChatGPT、網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)