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