摘要:否則不會得到異步之后的值對象的值,并沒有在中進行處理,而是直接作為返回值返回到對象外面了這就是的魔法。當生成器函數內的邏輯執行完畢且沒有錯誤之后,這個對象返回值變為狀態,且將生成器的返回值作為出來的值。
之前我在關于Promise的文章中提到了co這個庫。在這篇文章里,我將寫一寫自己對它的認識。
Trust me,用了co庫,你不想用別的,來它半斤異步調用你一口能吃仨。
但是我對Tj大神的co庫源碼談不上深入理解。所以,如有亂講,歡迎指正。
我這里默認讀者對Promise和Generator有一定的認識。
先安利自己寫的兩篇關于Promise的文章:
淺析ES6原生Promise
再談Promise
下面我就來談談co這個牛逼的庫。
ES7 async/await干嘛,我們不是講ES6么,怎么跳到ES7了?
因為co要做的事情,就是ES7的async/await要做的事情。
也就是說,這種解決異步的思路,已經在ECMA標準的考慮之中了。將來我們瀏覽器的JS引擎就可以原生實現這件事而不是通過JavaScript代碼模擬。要知道,引擎的實現和代碼的實現那是完全兩碼事。
多一句嘴:有些同學混淆了ECMA標準、引擎支持和代碼實現的聯系。
這里引用老趙在知乎里面回答問題時說的一句話:
ES7是個標準,定義的是what to do不是how to do,為什么好多人還是搞不清這兩者的區別。
ECMAScript定義了一些JavaScript語言層面要做的事情,這是一個標準。之所以要制定這個標準,是為了防止瀏覽器各自為政而出現JS引擎對同一行代碼的解釋出現不同的情況。
也就是說,ECMA制定標準,我們就可以按照這個標準來寫JavaScript代碼。寫好的JavaScript代碼由瀏覽器的JS引擎來解釋,最終變成計算機能讀懂的代碼來執行。
async/await上代碼:
var foo = function(){ return new Promise(resolve => { // 異步操作之后 resolve("OK"); }); } async funtion bar(){ var result = await foo(); console.log(result); } bar(); // ==> 打印"OK"
我們注意到,這段代碼用了兩個新的關鍵字async和await。而且有兩件神奇的事情發生了:
bar函數中包含了一個返回Promise對象的語句,而且Promise中存在異步代碼。但是這條語句接下來的語句明顯是等待Promise對象中的代碼異步執行完畢之后才執行的。(否則不會得到異步之后的值)
Promise對象resolve的值,并沒有在then中進行處理,而是直接作為返回值返回到Promise對象外面了.
這就是async/await的魔法。在函數前面加上async關鍵字之后,內部的代碼會識別await關鍵字。此時假設await后面的語句返回一個Promise對象,那么執行的代碼將會等待,直到Promise對象變為resolve狀態。并且Promise對象中resolve的值將直接作為await語句的返回值返回。然后再執行await語句之后的語句。
從此我們就可以無痛的擼異步代碼,媽媽再也不用擔心回調金字塔的出現和異步流程邏輯搞不定的情況了!
另一個奇妙的事情就是,率先支持這一特性的瀏覽器居然是微軟的Edge。大概是因為C#語言早就出現async/await,并且TypeScript也支持這一特性的緣故吧。
co我們希望所有的瀏覽器都及早支持這一特性。但是值得欣喜的一點就是,雖然V8還沒有支持,Tj大神早就利用Generator的方式實現了一個ES6版本的async/await!(膜拜臉)
co函數形式同樣是上面的邏輯,我們用co實現一次:
// 首先我們需要將co引入,假設我們使用commonJS的方式 const co = require("co"); var foo = function(){ return new Promise(resolve => { // 異步操作之后 resolve("OK"); }); } co(function* (){ var result = yield foo(); console.log(result); }); // ==> 打印"OK"
我們看到,co函數接收一個Generator生成器函數作為參數。執行co函數的時候,生成器函數內部的邏輯像async函數調用時一樣被執行。不同之處只是這里的await變成了yield。
簡單版本的co代碼要實現以上的邏輯,結合Generator的特性,co函數應該:
在函數體內將Generator生成器函數執行并生成生成器實例(在此命名為gen),然后通過gen.next方法的調用,不斷執行生成器函數內部的代碼。
執行next方法之后,返回的Promise在生成器函數執行環境之外執行,并取出resolve值,作為返回值作為next方法的參數返回到Generator執行環境中。
基于以上兩點,我們可以大體實現一個簡化版的co,代碼如下:
const co = function(genFunc){ const gen = genFunc(); // 得到生成器實例 const deal = (val) => { const res = gen.next(val); // 這里處理了異步邏輯, // 在回調中去遞歸,不斷執行next // 這樣就將resolve的值傳回了Generator res.value.then(result => deal(result)); } deal(); // 第一次觸發遞歸 }
去掉括號等等,只有短短六行代碼。
more原理性的東西大約就是這樣了。但是co做的不止這些。
之前co的yield后的語句并不支持Promise對象,而是一個特殊的函數,叫做thunk。目前co二者都支持。
此處我并不打算重復性解釋thunk版本,因為原理性的東西實現起來是差不多的。
co函數是有返回值的,也是一個Promise對象。
當生成器函數內的邏輯執行完畢且沒有錯誤之后,這個Promise對象(co返回值)變為resolve狀態,且將生成器的返回值作為resolve出來的值。
若生成器函數內返回一個Promise對象,那么co函數返回值就是這個Promise對象。
若生成器函數拋出了錯誤,那么這個錯誤作為reject出來的值,將Promise對象的狀態變為reject。
這樣我們就可以將錯誤放進其返回值的.catch方法中統一處理。
在生成器函數內部,我們也可以使用try...catch語句獲取錯誤對象。
生成器的yield后面可以跟一個元素值為Promise對象的數組,這個數組內Promise對象內的異步邏輯將并發執行,并返回一個數組。(類似于Promise.all方法)
假設生成器執行之前需要從外部傳入參數,co庫提供了一個方法:
var fn = co.wrap(function* (val) { return yield Promise.resolve(val); }); fn(true).then(function (val) { });結束
以上是一點微小的見解。謝謝指正。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/80191.html
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。寫一個符合規范并可配合使用的寫一個符合規范并可配合使用的理解的工作原理采用回調函數來處理異步編程。 JavaScript怎么使用循環代替(異步)遞歸 問題描述 在開發過程中,遇到一個需求:在系統初始化時通過http獲取一個第三方服務器端的列表,第三方服務器提供了一個接口,可通過...
摘要:主要通過處理二進制數據流,但是它并不支持字符編碼方式,需要通過模塊進行處理。最后留圖一張往期精彩回顧玩轉原理解析玩轉核心原理分析 一、前置知識 ??在理解koa-bodyparser原理之前,首先需要了解部分HTTP相關的知識。 1、報文主體 ??HTTP報文主要分為請求報文和響應報文,koa-bodyparser主要針對請求報文的處理。 ??請求報文主要由以下三個部分組成: 報文頭...
摘要:感謝大神的免費的計算機編程類中文書籍收錄并推薦地址,以后在倉庫里更新地址,聲音版全文狼叔如何正確的學習簡介現在,越來越多的科技公司和開發者開始使用開發各種應用。 說明 2017-12-14 我發了一篇文章《沒用過Node.js,就別瞎逼逼》是因為有人在知乎上黑Node.js。那篇文章的反響還是相當不錯的,甚至連著名的hax賀老都很認同,下班時讀那篇文章,竟然坐車的還坐過站了。大家可以很...
摘要:感謝大神的免費的計算機編程類中文書籍收錄并推薦地址,以后在倉庫里更新地址,聲音版全文狼叔如何正確的學習簡介現在,越來越多的科技公司和開發者開始使用開發各種應用。 說明 2017-12-14 我發了一篇文章《沒用過Node.js,就別瞎逼逼》是因為有人在知乎上黑Node.js。那篇文章的反響還是相當不錯的,甚至連著名的hax賀老都很認同,下班時讀那篇文章,竟然坐車的還坐過站了。大家可以很...
閱讀 1174·2021-09-27 13:34
閱讀 981·2021-09-13 10:25
閱讀 511·2019-08-30 15:52
閱讀 3450·2019-08-30 13:48
閱讀 648·2019-08-30 11:07
閱讀 2167·2019-08-29 16:23
閱讀 1993·2019-08-29 13:51
閱讀 2328·2019-08-26 17:42