摘要:前言在異步編程之一中實(shí)現(xiàn)了一個(gè)異步函數(shù)調(diào)用鏈,它是一個(gè)順序調(diào)用鏈,很類似責(zé)任鏈模式,但現(xiàn)實(shí)往往不是平鋪直敘的,更多的其實(shí)是峰回路轉(zhuǎn),本文將繼續(xù)討論更多的用法。
前言
在《ES6 異步編程之一:Generator》中實(shí)現(xiàn)了一個(gè)異步函數(shù)調(diào)用鏈,它是一個(gè)順序調(diào)用鏈,很類似責(zé)任鏈模式,但現(xiàn)實(shí)往往不是平鋪直敘的,更多的其實(shí)是峰回路轉(zhuǎn),本文將繼續(xù)討論更多Generator的用法。
作為函數(shù)的Generator在之前的示例中,我們更多的是把生成器作為一個(gè)迭代器來(lái)循環(huán)調(diào)用每個(gè)函數(shù),但忽視了生成器也是個(gè)函數(shù),意味著生成器內(nèi)部可以實(shí)現(xiàn)復(fù)雜的業(yè)務(wù)邏輯,以下的代碼通過(guò)yield等待文件讀取結(jié)果并對(duì)結(jié)果進(jìn)行特定的處理,
function* generator() { let r1 = yield get("a"); if (r1) { let r2 = yield get("b"); if (r2) { console.log(yield get("d")); } } else { console.log(yield get("c")); } } let g = generator(); g.next();
如果get是個(gè)異步調(diào)用,以上的代碼想要能夠執(zhí)行則需要get函數(shù)執(zhí)行得到結(jié)果后調(diào)用生成器的next方法來(lái)推進(jìn),這要求get函數(shù)能持有生成器對(duì)象,這顯然并不容易。
偏函數(shù)偏函數(shù)(Partial Function)是對(duì)函數(shù)定義域的子集定義的函數(shù),形式上就是指定任意部分參數(shù)生成一個(gè)新的函數(shù),如下:
function sum(a, b, c) { return a + b + c; } function sum1(a) { return function(b, c) { return a + b + c; }; } function sum2(a, b) { return function(c) { return a + b + c; }; } sum(1, 2, 3) == sum1(1)(2, 3); //true sum(1, 2, 3) == sum2(1, 2)(3); //true
一般在設(shè)計(jì)異步調(diào)用api時(shí),我們總是聲明一個(gè)參數(shù)來(lái)接收回調(diào)函數(shù),當(dāng)和偏函數(shù)相結(jié)合就變成這樣:
function get(f, callback) { delay(100, function(s) { callback(s + ":get " + f); }); } get("a", func); //調(diào)用get時(shí)必須立即傳入一個(gè)函數(shù) //轉(zhuǎn)換成偏函數(shù)形式: function partialGet(f) { return function(callback) { delay(100, function(s) { callback(s + ":get " + f); }); }; } let pGet = partialGet("a"); //可以先生成一個(gè)函數(shù) pGet(func); //需要時(shí)再傳入回調(diào)函數(shù)執(zhí)行
從上面的例子中可以發(fā)現(xiàn),偏函數(shù)能使定義和執(zhí)行分離,說(shuō)來(lái)巧了,生成器可用于定義業(yè)務(wù)邏輯而生成器的next用于推進(jìn)業(yè)務(wù)執(zhí)行,二者也是相互分離的。
生成器和偏函數(shù)基于前面這么多鋪墊,假設(shè)get就是一個(gè)偏函數(shù),如下:
function get(f) { return function(callback) { delay(100, function(s) { callback(s + ":get " + f); }); }; }
這意味著,yield get("a")使得next函數(shù)執(zhí)行的結(jié)果其value屬性值是個(gè)函數(shù),該函數(shù)的參數(shù)是一個(gè)能接收get異步結(jié)果的回調(diào)函數(shù),即:
g.next().value(function(value) { g.next(value); //value成為yield的返回并繼續(xù)推進(jìn)業(yè)務(wù)邏輯 });
通過(guò)遞歸可以不斷的執(zhí)行生成器的next方法,一個(gè)全新的通過(guò)生成器來(lái)實(shí)現(xiàn)業(yè)務(wù)邏輯的run方法便呼之欲出了,
function run(gen) { let g = gen(); function next(lastValue) { let result = g.next(lastValue); //將上一個(gè)異步執(zhí)行結(jié)果傳出給當(dāng)前的yield并執(zhí)行下一個(gè)yield if (result.done) { return result.value; } //value是偏函數(shù)返回的新函數(shù),它的參數(shù)是個(gè)用來(lái)接收異步結(jié)果的回調(diào)函數(shù) result.value(next); //next作為接收異步結(jié)果的回調(diào)函數(shù) } next(); } run(generator);
綜合以上例子不難發(fā)現(xiàn)另外一個(gè)好處,通過(guò)偏函數(shù)可以使異步調(diào)用api不受生成器的侵入,《ES6 異步編程之一:Generator》中實(shí)現(xiàn)的異步調(diào)用需要將生成器作為參數(shù),有興趣的話你可以嘗試改造一下之前的示例。
現(xiàn)在通過(guò)新編寫(xiě)的run函數(shù)就可以來(lái)執(zhí)行本文一開(kāi)始編寫(xiě)的那個(gè)生成器了。
thunkify偏函數(shù)的方案對(duì)api和生成器也是有侵入的,他要求:
api必須是偏函數(shù)形式;
生成器定義業(yè)務(wù)邏輯,每個(gè)yield 后面的函數(shù)必須是調(diào)用偏函數(shù);
第二個(gè)問(wèn)題是本方案的核心機(jī)制所要求,但第一個(gè)問(wèn)題我們可以通過(guò)thunkify來(lái)解決,api依舊按照get(value, callback)方式定義,但定義生成器時(shí)需要將異步api調(diào)用通過(guò)thunkify轉(zhuǎn)換為偏函數(shù),如下:
let Thunkify = require("thunkify"); let thunkifiedGet = Thunkify(get); function get(f, callback) { delay(100, function(s) { callback(s + ":get " + f); }); } function* generator() { let r1 = yield thunkifiedGet("a"); if (r1) { let r2 = yield thunkifiedGet("b"); if (r2) { console.log(yield thunkifiedGet("d")); } } else { console.log(yield thunkifiedGet("c")); } }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/81484.html
摘要:回調(diào)函數(shù)這是異步編程最基本的方法。對(duì)象對(duì)象是工作組提出的一種規(guī)范,目的是為異步編程提供統(tǒng)一接口。誕生后,出現(xiàn)了函數(shù),它將異步編程帶入了一個(gè)全新的階段。 更多詳情點(diǎn)擊http://blog.zhangbing.club/Ja... Javascript 語(yǔ)言的執(zhí)行環(huán)境是單線程的,如果沒(méi)有異步編程,根本沒(méi)法用,非卡死不可。 為了解決這個(gè)問(wèn)題,Javascript語(yǔ)言將任務(wù)的執(zhí)行模式分成兩種...
摘要:傳統(tǒng)的異步方法回調(diào)函數(shù)事件監(jiān)聽(tīng)發(fā)布訂閱之前寫(xiě)過(guò)一篇關(guān)于的文章,里邊寫(xiě)過(guò)關(guān)于異步的一些概念。內(nèi)部函數(shù)就是的回調(diào)函數(shù),函數(shù)首先把函數(shù)的指針指向函數(shù)的下一步方法,如果沒(méi)有,就把函數(shù)傳給函數(shù)屬性,否則直接退出。 Generator函數(shù)與異步編程 因?yàn)閖s是單線程語(yǔ)言,所以需要異步編程的存在,要不效率太低會(huì)卡死。 傳統(tǒng)的異步方法 回調(diào)函數(shù) 事件監(jiān)聽(tīng) 發(fā)布/訂閱 Promise 之前寫(xiě)過(guò)一篇關(guān)...
摘要:環(huán)境中產(chǎn)生異步操作的函數(shù)分為兩大類計(jì)時(shí)函數(shù)和函數(shù)。如果要在應(yīng)用中定義復(fù)雜的異步操作,就要使用者兩類異步函數(shù)作為基本的構(gòu)造快。在本例子中同步事件循環(huán)不包含內(nèi)部的外部的異步事件循環(huán)內(nèi)部的。其弊端是操作強(qiáng)耦合維護(hù)代價(jià)高。 JavaScript環(huán)境中產(chǎn)生異步操作的函數(shù)分為兩大類:計(jì)時(shí)函數(shù)和I/O函數(shù)。如果要在應(yīng)用中定義復(fù)雜的異步操作,就要使用者兩類異步函數(shù)作為基本的構(gòu)造快。本文沒(méi)有對(duì)某個(gè)知識(shí)點(diǎn)...
摘要:生成器是原生提供的異步編程方案,其語(yǔ)法行為和傳統(tǒng)函數(shù)完全不同,阮大的入門(mén)一書(shū)中對(duì)生成器有比較詳盡的介紹,還有一些其他的文章可以參考,比如入門(mén)深入淺出三生成器深入淺出十一生成器,續(xù)篇本文主要是通過(guò)一些代碼示例來(lái)記錄和總結(jié)生成器的用法。 Generator 生成器是es6原生提供的異步編程方案,其語(yǔ)法行為和傳統(tǒng)函數(shù)完全不同,阮大的《ECMAScript 6 入門(mén)》一書(shū)中對(duì)生成器有比較詳盡的...
摘要:更好的異步編程上面的方法可以適用于那些比較簡(jiǎn)單的異步工作流程。小結(jié)的組合目前是最強(qiáng)大,也是最優(yōu)雅的異步流程管理編程方式。 訪問(wèn)原文地址 generators主要作用就是提供了一種,單線程的,很像同步方法的編程風(fēng)格,方便你把異步實(shí)現(xiàn)的那些細(xì)節(jié)藏在別處。這讓我們可以用一種很自然的方式書(shū)寫(xiě)我們代碼中的流程和狀態(tài)邏輯,不再需要去遵循那些奇怪的異步編程風(fēng)格。 換句話說(shuō),通過(guò)將我們generato...
閱讀 852·2021-11-24 09:38
閱讀 1061·2021-11-11 11:01
閱讀 3324·2021-10-19 13:22
閱讀 1597·2021-09-22 15:23
閱讀 2921·2021-09-08 09:35
閱讀 2829·2019-08-29 11:31
閱讀 2194·2019-08-26 11:47
閱讀 1625·2019-08-26 11:44