如何優雅處理 async await 錯誤——解讀小而美的 await-to-js 庫

大家好,我是若川。持續組織了5個月源碼共讀活動,感興趣的可以點此加我微信 ruochuan12?參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》?包含20余篇源碼文章。

這是源碼共讀活動第21期 await-to-js,優雅的處理 async await 的 try-catch,讀者掘金@愛嘿嘿的小黑 的投稿。

1前言

學而不思則罔

最近有在讀一些比較優秀的npm包的代碼,起因是感覺自己現在寫的代碼還是不夠規范,不夠簡潔。

可是我又不知道到底什么樣的代碼才算是比較的代碼,在進行一番思考過后我認為還是要站在巨人的肩膀上。

通過閱讀優秀的源碼并從中學習如何寫出讓人覺得賞心悅目的代碼最后再寫文進行章總結對整個學習的過程進行一個梳理同時分享給其他人。

為什么要在開頭寫這么多呢?因為我需要為自己堅持下去找一個理由。這樣我才能乘風破浪,一往無前。

話不多說,開始總結。

2JS異步編程進化之路

回調地獄階段

在正式介紹await-to-js這個庫之前,讓我們先簡單的回顧一下有關于在JavaScript這門語言中,異步編程的進化之路。在Promise沒出現之前,異步編程一直是困擾著前端工程師的一個大難題,當時的前輩可能會經常看到下面這種代碼。

function?AsyncTask()?{asyncFuncA(function(err,?resultA){if(err)?return?cb(err);asyncFuncB(function(err,?resultB){if(err)?return?cb(err);asyncFuncC(function(err,?resultC){if(err)?return?cb(err);//?And?so?it?goes....});});});
}

這種同時在縱向和橫向延伸的回調中嵌套著回調的代碼又被稱為回調地獄。可見這玩意讓人多么惡心,具體來說有以下這幾個缺點

  • 難以維護(看都不想看,還維護個**)

  • 難以捕捉到錯誤(一個一個找?) 總而言之,這個問題在當時是很需要被解決的,所以在ES6中,出現了Promise。

Promise階段

Promise是一種優雅的異步編程解決方案。從語法上來將,它是一個對象, 代表著一個異步操作最終完成或失敗,從語意上來講,它是承諾,承諾過一段時間給你一個結果。

由于它的原型存在then,catch,finally會返回一個新的promise所以可以允許我們鏈式調用,解決了傳統的回調地獄的問題。

由于它本身存在all方法,所以可以支持多個并發請求,獲取并發請求中數據。

有了Promise后,上面的代碼可以被寫成下面這樣。

function?asyncTask(cb)?{asyncFuncA.then(AsyncFuncB).then(AsyncFuncC).then(AsyncFuncD).then(data?=>?cb(null,?data).catch(err?=>?cb(err));
}

相比較于上面的回調地獄,使用Promise可以幫助我們讓代碼只在縱向發展,并且提供了處理錯誤的回調。顯然優雅了很多。不過就算Promise已經這么優秀了,可是依然存在兩個每種不足的地方

  • 不夠同步(代碼依然會縱向延伸)

  • 不能給每一次異步操作都進行錯誤處理 這也就是為什么ES7中會出現async/await,號稱異步編程的最后解決方案的原因了。

async/await

async 函數是 Generator 函數的語法糖。使用 關鍵字 async 來表示,在函數內部使用 await 來表示異步。相較于 Generatorasync 函數的改進在于下面四點:

  • 內置執行器Generator 函數的執行必須依靠執行器,而 async 函數自帶執行器,調用方式跟普通函數的調用一樣

  • 更好的語義asyncawait 相較于 *yield 更加語義化

  • 更廣的適用性co 模塊約定,yield 命令后面只能是 Thunk 函數或 Promise對象。而 async 函數的 await 命令后面則可以是 Promise 或者 原始類型的值(Number,string,boolean,但這時等同于同步操作)

  • 返回值是 Promiseasync 函數返回值是 Promise 對象,比 Generator 函數返回的 Iterator 對象方便,可以直接使用 then() 方法進行調用

此處總結參考自:理解async/await[1]

有了async/await,上面的代碼可以被改寫成下面這樣

function?async?asyncTask(cb)?{const?asyncFuncARes?=?await?asyncFuncA()const?asyncFuncBRes?=?await?asyncFuncB(asyncFuncARes)const?asyncFuncCRes?=?await?asyncFuncC(asyncFuncBRes)
}

同時我們可以對每一次異步操作進行錯誤處理

function?async?asyncTask(cb)?{try?{const?asyncFuncARes?=?await?asyncFuncA()}?catch(error)?{return?new?Error(error)}try?{const?asyncFuncBRes?=?await?asyncFuncB(asyncFuncARes)}?catch(error)?{return?new?Error(error)}try?{const?asyncFuncCRes?=?await?asyncFuncC(asyncFuncBRes)}?catch(error)?{return?new?Error(error)}
}

這樣一來上面Promise存在的兩個每種不足的地方是不是就被優化了呢?所以說async/await是JS中異步編寫的最后解決方案我個人覺得一點問題沒有,但是我不知道你看上面的代碼,每一次異步操作都要用try/catch進行錯誤處理是不是感覺不夠方便不夠智能呢?

3await-to-js-小而美的npm包

基本用法

作者是這樣介紹這個庫的

Async await wrapper for easy error handling without try-catch。

中文翻譯過來就是

無需 try-catch 即可輕松處理錯誤的異步等待包裝器。

這里做個簡單的對比,之前我們在異步操作中處理錯誤的方法是這樣的

function?async?asyncTask()?{try?{const?asyncFuncARes?=?await?asyncFuncA()}?catch(error)?{return?new?Error(error)}try?{const?asyncFuncBRes?=?await?asyncFuncB(asyncFuncARes)}?catch(error)?{return?new?Error(error)}try?{const?asyncFuncCRes?=?await?asyncFuncC(asyncFuncBRes)}?catch(error)?{return?new?Error(error)}
}

而用了await-to-js之后,我們可以這樣的處理錯誤

import?to?from?'./to.js';
function?async?asyncTask()?{const?[err,?asyncFuncARes]??=?await?to(asyncFuncA())if(err)?throw?new?(error);const?[err,?asyncFuncBRes]??=?await?tp(asyncFuncB(asyncFuncARes))if(err)?throw?new?(error);const?[err,?asyncFuncCRes]??=?await?to(asyncFuncC(asyncFuncBRes)if(err)?throw?new?(error);
}

是不是簡潔多了呢?

作者究竟用了什么黑魔法?

你可能不信,源碼只有僅僅15行。

源碼分析

export?function?to<T,?U?=?Error>?(promise:?Promise<T>,errorExt?:?object
):?Promise<[U,?undefined]?|?[null,?T]>?{return?promise.then<[null,?T]>((data:?T)?=>?[null,?data]).catch<[U,?undefined]>((err:?U)?=>?{if?(errorExt)?{const?parsedError?=?Object.assign({},?err,?errorExt);return?[parsedError,?undefined];}return?[err,?undefined];});
}export?default?to;

上面這里是TS版的源碼,但是考慮到有些同學可能還沒接觸過TS,我著重分析一下下面這版JS版的源碼。

export?function?to(promise,?errorExt)?{return?promise.then((data)?=>?[null,?data]).catch((err)?=>?{if?(errorExt)?{const?parsedError?=?Object.assign({},?err,?errorExt);return?[parsedError,?undefined];}return?[err,?undefined];});
}
export?default?to;

這里我們先拋開errorExt這個自定義的錯誤文本,核心代碼是這樣的

export?function?to(promise)?{return?promise.then((data)?=>?[null,?data])?//?成功,返回[null,響應結果].catch((err)?=>?{return?[err,?undefined];?//?失敗,返回[錯誤信息,undefined]});
}
export?default?to;

可以看出,其代碼的邏輯用中文解釋是這樣的

  • 無論成功還是失敗都返回一個數組,數組的第一項是和錯誤相關的,數組的第二項是和響結果相關的

  • 成功的話數組第一項也就是錯誤信息為空,數組第二項也就是響應結果正常返回

  • 失敗的話數組第一項也就是錯誤信息為錯誤信息,數組第二項也就是響應結果返回undefined

經過上面的分析我們可以認定,世界上沒有什么黑魔法,沒有你做不到,只有你想不到。

這里我們再來看函數to的第二個參數errorExt不難發現,這玩意其實就是拿來用戶自定義錯誤信息的,通過Object.assign將正常返回的error和用戶自定義和合并到一個對象里面供用戶自己選擇。

4結語

源碼不可怕,可怕的是自己的面對未知的恐懼感。

敢于面對,敢于嘗試,才能更上一層樓。

繼續加油,少年。

關注我,vx:codebangbang,掘金:愛嘿嘿的小黑。

5參考資料

  • 倉庫地址:https://github.com/scopsy/await-to-js

  • 官方文章:How to write async await without try-catch blocks in Javascript[2]

參考資料

[1]

https://segmentfault.com/a/1190000010244279: https://link.juejin.cn?target=https%3A%2F%2Fsegmentfault.com%2Fa%2F1190000010244279

[2]

How to write async await without try-catch blocks in Javascript: https://blog.grossman.io/how-to-write-async-await-without-try-catch-blocks-in-javascript/


34140d070049a3f30ea9ad3bfbea8bea.gif

·················?若川簡介?·················

你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列》20余篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會寫一篇年度總結,已經寫了7篇,點擊查看年度總結。
同時,最近組織了源碼共讀活動,幫助3000+前端人學會看源碼。公眾號愿景:幫助5年內前端人走向前列。

94116725d2da2fe8d5183b2497b1691e.png

識別方二維碼加我微信、拉你進源碼共讀

今日話題

略。分享、收藏、點贊、在看我的文章就是對我最大的支持~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/274988.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/274988.shtml
英文地址,請注明出處:http://en.pswp.cn/news/274988.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

同態加法_同態的Spotify

同態加法重點 (Top highlight)When neumorphism was predicted to be one of the top 2020 UI design trends, I wanted to give it a shot. Having said that, I wanted to explore a type that had not gone overboard, neumorphism in Dark Mode.當neumorphism預計為頂部202…

ubuntu清除無效的右鍵打開方式

為什么80%的碼農都做不了架構師&#xff1f;>>> 今天安裝了幾個程序又將它們刪除了之后發現了一個比較嚴重的后遺癥&#xff0c;在相關文件右鍵打開方式中出現了許多實際已經不存在的文件打開程序名。想了多種方法去除&#xff0c;可是效果不佳&#xff0c;最終采用…

咖啡豆(JavaBean)?香

Sun公司對JavaBean的定義為:可以重復利用的軟件組件&#xff0c;它在遵循JavaBean技術規范的基礎上提供特定的功能&#xff0c;這些功能模塊可以組成更大規模的應用系統。 到底什么是JavaBean? 先看一段代碼&#xff1a; /** * author yong * */ public class Add { public st…

新一代的編譯工具 SWC,97年小哥寫的~

大家好&#xff0c;我是若川。持續組織了5個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。最近前端圈掀起了一…

開始學習jQuery和準備工作

<script>$(document).ready(function(){}); 首先&#xff0c;在頁面頂部添加一行script元素&#xff0c;然后在下一行寫上結束符。 瀏覽器會運行script里所有的Javascript&#xff0c;包括jQuery。 在你的script元素里&#xff0c;添加這段代碼&#xff1a;$(document).r…

粉紅噪音_粉紅的常綠力量

粉紅噪音I use Instagram. But I don’t use Instagram in the way that my daughters, who are 21 and 14, use Instagram. More to the point, Instagram doesn’t use me in quite the same way it uses my daughters.我使用Instagram。 但是&#xff0c;我不會像21歲和14歲…

Sql Server 中存儲過程的output return的區別

看http://zxianf.blog.163.com/blog/static/301207012009114104124969/中片關于Sql Server中存儲過程output和return值的區別 在里面有講解&#xff0c;我在自己本機中測試的結果如下&#xff0c; 1&#xff1a;ReturnValue只能返回0,1,-1這樣的數據&#xff0c;局限性很大 &am…

1個月增長15000 star,zx 庫寫shell腳本真不錯~

大家好&#xff0c;我是若川。持續組織了5個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。今天來討論一個牛逼…

灰色邊框陰影_50種暗模式灰色陰影

灰色邊框陰影If you’re an avid dark mode user like me, you’ll know that dark mode isn’t just about white text on black backgrounds. In a single app, a handful of shades of gray give the app some depth. And across various apps, the spectrum of gray become…

Android源代碼下載

為什么80%的碼農都做不了架構師&#xff1f;>>> Android代碼使用git管理, 所以關于Android源碼下載一般來說要安裝git. 本文是講述只使用Eclipse完成Android源碼下載和關聯. 下載Eclipse,目前最新版本是Juno,自帶了EGit插件-->Eclipse Git插件 那么可以使用EGit…

關于nginx調轉404錯誤頁面

在server{}模塊添加如下&#xff1a; error_page 404 /404.html; location /404.html { root /var/www/html/sina/; #“404目錄地址” }轉載于:https://www.cnblogs.com/alang85/archive/2012/03/01/404_error.html

尤雨溪:Vue 3 將成為新的默認版本

過完年&#xff0c;大年初七&#xff0c;Vue3 將成為默認版本&#xff0c;這時感覺我之前寫的幾篇文章都可以抽空更新一版了。尤雨溪推薦神器 ni &#xff0c;能替代 npm/yarn/pnpm &#xff1f;簡單好用&#xff01;源碼揭秘&#xff01;Vue 3.2 發布了&#xff0c;那尤雨溪是…

shell編程系列20--文本處理三劍客之awk常用選項

shell編程系列20--文本處理三劍客之awk常用選項awk選項總結選項 解釋 -v 參數傳遞 -f 指定腳本文件 -F 指定分隔符 -V 查看awk的版本號[rootlocalhost shell]# awk -v num2"$num1" -v var1"$var" BEGIN{print num2,var…

v-charts加載動畫_加載動畫-用戶體驗寫作練習

v-charts加載動畫Many new UX writers often struggle to find the balance between creativity and clarity. You can’t make everything fun/exciting/interesting as it can have an adverse effect on usability. But there are times when you can add a bit of flair.許…

linux 常用命令收集

關機&#xff1a;poweroff&#xff0c;shutdown -h now&#xff0c;init 0重啟&#xff1a;reboot&#xff0c;shutdown -r now&#xff0c;init 6 關閉x-window&#xff1a;init 3啟動x-window&#xff1a;init 5&#xff0c;start x1.終止命令&#xff1a;ctrlc 2.結束輸入…

34歲回顧人生,也怕中年危機!

大家好&#xff0c;我是若川。持續組織了5個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。最近發生一件令人感…

蛋花花APP,APP開發這幾點你要注意了

蛋花花君又來了&#xff0c;這次蛋花花君為大家分享的是APP開發過程中需要注意的幾點。 1、用戶體驗 程序猿蛋花花覺得&#xff0c;APP開發是為客戶來開發的&#xff0c;而不單單是為了老板&#xff0c;畢竟真正使用的是廣大用戶。APP的設計應該從用戶的角度出發&#xff0c;提…

svg動畫制作_制作第一個SVG動畫

svg動畫制作Story of a designer trying to code animations instead of asking a dev to figure it out.一位設計師嘗試編寫動畫代碼而不是要求開發人員弄清楚動畫的故事。 編碼動畫是Webdesign的未來 (Coded animations are the future of Webdesign) Because we have acces…

網站前端設計,從960框架開始

一個網站進入到前端設計階段&#xff0c;第一步肯定是為全站搭建一個統一的&#xff0c;基礎的HTML模型&#xff0c;在這里推薦一下我剛學習的960框架。960是一個CSS框架&#xff0c;你肯定在想&#xff0c;這個世界肯定是瘋了&#xff0c;連CSS都有框架了嗎&#xff0c;沒錯&a…

60+ 實用 React 工具庫,助力你高效開發!

大家好&#xff0c;我是若川。持續組織了5個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。最近看到一些實用的…