如何优雅处理 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.mzph.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;最终采用…

新一代的编译工具 SWC,97年小哥写的~

大家好&#xff0c;我是若川。持续组织了5个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。最近前端圈掀起了一…

粉红噪音_粉红的常绿力量

粉红噪音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…

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.许…

34岁回顾人生,也怕中年危机!

大家好&#xff0c;我是若川。持续组织了5个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。最近发生一件令人感…

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余篇源码文章。最近看到一些实用的…

2012年12月第二个周末

2019独角兽企业重金招聘Python工程师标准>>> 这周&#xff0c;装上了windows版的 Linux版的oracle 熟悉了下SQL*PLUS的编程规则&#xff0c;还有常用的linux命令 看了一本《简爱》 正在看oracle 转载于:https://my.oschina.net/u/204616/blog/545513

『C#基础』调用CMD的一个小工具

由于经常要使用CMD的一些命令&#xff0c;比如查看IP&#xff0c;Ping一个网址之类的。于是就写了一个调用CMD.exe的小工具。 主要就是实现这样一个事情&#xff1a;调用CMD.exe然后传给它我想要执行的命令&#xff0c;最后获取结果。 界面&#xff1a; 代码&#xff1a; 主要执…

小姐姐:如何参与大型开源项目-Taro 共建

大家好&#xff0c;我是若川。持续组织了5个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。“本文来自前端程序…

JavaWeb学习总结(十七)——JSP中的九个内置对象

2019独角兽企业重金招聘Python工程师标准>>> 一、JSP运行原理 每个JSP 页面在第一次被访问时&#xff0c;WEB容器都会把请求交给JSP引擎&#xff08;即一个Java程序&#xff09;去处理。JSP引擎先将JSP翻译成一个_jspServlet(实质上也是一个servlet) &#xff0c;然…

C#网络编程(异步传输字符串) - Part.3[转自JimmyZhang博客]

源码下载&#xff1a;http://www.tracefact.net/SourceCode/Network-Part3.rar C#网络编程(异步传输字符串) - Part.3 这篇文章我们将前进一大步&#xff0c;使用异步的方式来对服务端编程&#xff0c;以使它成为一个真正意义上的服务器&#xff1a;可以为多个客户端的多次请求…

chrome黑暗模式_黑暗模式:如何克服黑暗面

chrome黑暗模式This article has been written by Redmadrobot Design Lab. Translated and reposted with permission by Alconost Inc., professional translation and localization company.本文由 Redmadrobot设计实验室 撰写 。 经过 专业翻译和本地化公司 Alconost Inc.的…

Deco 智能代码体验版正式上线啦,快来体验设计稿一键生成代码~

Deco 是什么&#xff1f;—Deco 智能代码项目是我们团队在「前端智能化」方向上的探索&#xff0c;其聚焦设计稿一键生成多端代码这一切入点&#xff0c;实现将 Sketch/Photoshop 等设计稿进行解析并直接生成多端代码&#xff08;Taro/React/Vue&#xff09;的能力。Deco 可以使…