JS中如何优雅的使用async await详解
作者:尽管如此世界依然美丽 发布时间:2024-05-02 16:19:23
目录
jQuery的$.ajax
Webpack时代的开始
深入了解Promise
消灭嵌套
await-to-js
总结
jQuery的$.ajax
在开始之前我们先来聊聊我的js异步之路。在我还在学校的时候,那时候还是 jQuery 的天下,我直接接触到并且经常使用的异步操作就是网络请求,一手 $.ajax 走天下,伴我过了大二到毕业后差不多大半年的时间。
$.ajax( "/xxx" )
.done(function() {
// success !!! do something...
})
.fail(function() {
// fail !!! do something...
})
.always(function() {
// loading finished..
});
不可否认,$.ajax 这个东西还是挺好使的,在面对大部分场景只有一个请求的情况下,完全胜任甚至觉得很棒
但是有个大大的问题,那就是面对请求链的时候就会特别特别的糟心,比如一个请求依赖于另一个请求的结果,两个可能还无所谓,要是五个八个的,可能想要直接 * 。。。
$.ajax('/xxx1')
.done(function() {
// success !!! do something...
$.ajax('/xxx2')
.done(function() {
// success !!! do something...
$.ajax('/xxx3')
.done(function() {
// success !!! do something...
$.ajax('/xxx4')
.done(function() {
// success !!! do something...
$.ajax('/xxx5')
.done(function() {
// success !!! do something...
// more...
})
.fail(function() {
// fail !!! do something...
})
.always(function() {
// loading finished..
});
})
.fail(function() {
// fail !!! do something...
})
.always(function() {
// loading finished..
});
})
.fail(function() {
// fail !!! do something...
$.ajax('/xxx6')
.done(function() {
// success !!! do something...
$.ajax('/xxx7')
.done(function() {
// success !!! do something...
// more....
})
.fail(function() {
// fail !!! do something...
})
.always(function() {
// loading finished..
});
})
.fail(function() {
// fail !!! do something...
})
.always(function() {
// loading finished..
});
})
.always(function() {
// loading finished..
});
})
.fail(function() {
// fail !!! do something...
})
.always(function() {
// loading finished..
});
})
.fail(function() {
// fail !!! do something...
})
.always(function() {
// loading finished..
});
抱歉,我不知道你可以套这么多层。。。,但事实就是TM经常出现这样的流程,大伙儿说说,这不能怪产品吧???只能怪自己学艺不精
像这样链式操作,我觉得吧,是个人可能都是奔溃的,先不说代码的可读性,就拿天天在变化的产品需求来说,也许先前是 请求1 结束之后紧接着 请求2 、 请求3 ,后面产品大手一挥,我觉得这个流程不大对,后面就变成了 请求2、 请求3 、 请求1,这尼玛套娃怎么改?可能有人会有疑问,为啥不用 axios 、 await 、async 呢?这个就不得不提项目代码是08年开写的JSP了。。。。在整了大半年的屎上拉屎以后,迎来了大大的转机,新写的项目开始往 Vue 上面转,并且放弃一部分兼容性,我TM直接起飞。。。
Webpack时代的开始
新的项目直接Vue + Webpack,我直接就给安排上 axios 、 await 、async ,现在代码非常好使,嵌套N层的代码没了
const r1 = await doSomthing1();
if (r1.xxx === 1) {
const r2 = await doSomthing2(r1);
const r3 = await doSomthing3(r2);
// do something....
} else {
const r4 = await doSomthing4(r1);
const r5 = await doSomthing5(r4);
// do something....
}
// do something....
但是上面的代码存在一个问题,如果某个任务报错,那么代码直接就终止了。。。这样不符合我们的预期啊,那我们加上 try catch
let r1;
try {
r1 = await doSomthing1();
} catch (e) {
// do something...
return;
}
if (r1) {
if (r1.xxx === 1) {
let r2;
try {
r2 = await doSomthing2(r1);
} catch (e) {
// do something...
return;
}
if (r2) {
let r3;
try {
r3 = await doSomthing3(r2);
} catch (e) {
// do something...
return;
}
// do something...
}
} else {
let r4;
try {
r4 = await doSomthing4(r1);
} catch (e) {
// do something...
return;
}
if (r4) {
let r5;
try {
r5 = await doSomthing5(r4);
} catch (e) {
// do something...
return;
}
}
// do something...
}
// do something...
}
???
优化了,等于没优化。。。
这时候我想聪明的小伙伴可能会说了,这是啥煎饼玩意儿。而呆滞的小伙伴已经开始想怎么解决这样的问题了。。。
深入了解Promise
我们来看一下 Promise 的定义
/**
* Represents the completion of an asynchronous operation
*/
interface Promise<T> {
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;
/**
* Attaches a callback for only the rejection of the Promise.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of the callback.
*/
catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>;
}
then 和 catch 都会返回一个新的 Promise ,我相信很多小伙伴都已经想到了怎么解决方法,需要使用 try catch 是因为它会报错,那我们返回一个 永远不会报错的结果 不就行了?说干就干
消灭嵌套
function any(promise) {
return promise.then((v) => v).catch((_) => null);
}
这样就完全解决了啊???通过判断是否有值来判断是否成功,就不用再写 try catch 了,但是这样的代码有点不大好使,如果 then 返回的是一个 void 那么就完犊子了,一个 undefined 一个 null ,这还判断个锤子,我们再来改进一下
function any(promise) {
return promise
.then((v) => ({ ok: v, hasErr: false }))
.catch((e) => ({ err: e, hasErr: true }));
}
使用的话
const r = await any(doSomething());
if (r.hasErr) {
console.log(r.err);
return;
}
console.log(r.ok);
现在看起来是不是很完美呢,赶紧和小伙伴推销一下。
小伙伴:???这啥煎饼玩意儿,不用不用。
我:这个我写的,在异步中用起来很好使的,告别嵌套 try catch ,巴拉巴拉。。。
小伙伴:好的,下次一定用。
大家肯定有遇到过这样的情况,大家写的代码互相看不起,只要不是三方库,大家都是能不用同事写的就不用。。。
await-to-js
我都以为只有我一人欣赏,这一份优雅。事情出现转机,某天我正在刷github,发现了一个和我差不多异曲同工之妙的东西 await-to-js ,几行代码透露了和我一样的执着
// 下面是最新的代码
/**
* @param { Promise } promise
* @param { Object= } errorExt - Additional Information you can pass to the err object
* @return { Promise }
*/
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) {
Object.assign(err, errorExt);
}
return [err, undefined];
});
}
export default to;
再贴上使用示例
import to from 'await-to-js';
// If you use CommonJS (i.e NodeJS environment), it should be:
// const to = require('await-to-js').default;
async function asyncTaskWithCb(cb) {
let err, user, savedTask, notification;
[ err, user ] = await to(UserModel.findById(1));
if(!user) return cb('No user found');
[ err, savedTask ] = await to(TaskModel({userId: user.id, name: 'Demo Task'}));
if(err) return cb('Error occurred while saving task');
if(user.notificationsEnabled) {
[ err ] = await to(NotificationService.sendNotification(user.id, 'Task Created'));
if(err) return cb('Error while sending notification');
}
if(savedTask.assignedUser.id !== user.id) {
[ err, notification ] = await to(NotificationService.sendNotification(savedTask.assignedUser.id, 'Task was created for you'));
if(err) return cb('Error while sending notification');
}
cb(null, savedTask);
}
async function asyncFunctionWithThrow() {
const [err, user] = await to(UserModel.findById(1));
if (!user) throw new Error('User not found');
}
是不是感觉回来了,嵌套不再。。。
为了让小伙伴用上一行的代码,我只能忍痛推荐 await-to-js ,发上github地址,小伙伴:八百多star (ps: 现在2K+) 质量可靠,看了一下示例,嗯嗯,很不错,很完美,后面。。。后面的事不用我多说了,我自己写的也全换成了 await-to-js 。。。
我待世界如初恋,初恋却伤我千百遍
$.ajax
Promise
await-to-js
来源:https://juejin.cn/post/7014749066005331975


猜你喜欢
- 这篇文章主要介绍了js简单的分页器插件代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参
- ChainMap是Python collections模块中的一个成员,它用来将多个map组合到一起。Chain是链条的意思,字面意思就是把
- 之前版本的代理中,可以使用fiddler进行HTTP包的代理,但是代理HTTPS包时,执行错误 self._sslobj.do_
- hello,我是小小炽,这是我写的第一篇博客,写博客一直都想在写,但是苦于能力尚浅,在各位大牛面前那既然是关公面前耍大刀了,但是其实想来每一
- 无论何时,IE总是让页面制作者感到那么的黯然销魂,尤其是IE6,IE7次之,虽然IE8已经做了很大的改进,但由于XP用户的数量实在太大,而且
- 前言相信大家都知道当声明一个变量,并且没有给赋值的情况下,它的初始值是undefined。但是在javascript中,怎么检查一个值是否为
- 1. 用Dreamweaver 4.0轻松设计会自动弹性调整的网页 首先需要保证的是你的页面内容采用了表格的格式,然后打开你要编辑的页面,按
- 【原文地址】 Tip/Trick: How to upload a .SQL file to a Hoster and
- 正文之前前阵子做了个《人工智能》 的课程作业,然后写了个人工智障。。。大概就是个可以跟你下五子棋的傻儿子。。。下面是代码和效果正文 1、 摘
- 在实际应用过程中,只要保证选项卡模块结构代码的完整性,就可以任意添加N个同类选项卡,不需要手动在HTML里绑定事件处理程序以及给要隐藏显示的
- 题目:给一个列表,找元素在此列表中的位置,如果找到,返回此元素的下标,如果找不到,那就直接返回空解决方法1:# _*_ coding:UTF
- 比如user_num表:例1:查询出现过2次的user往往初学者会错误地认为在where 语句里直接使用count()算法,很显然这个想法是
- 在web开发中经常用到验证码,为了防止机器人注册或者恶意登陆和查询等,作用不容小觑但是验证码其实不是一个函数就能搞定的,它需要生成图片和水印
- 由于工作中涉及到生日编辑资料编辑,然后自己改了一下代码:<html><head> <meta charset=
- 本文实例讲述了PHP基于迭代实现文件夹复制、删除、查看大小等操作的方法。分享给大家供大家参考,具体如下:前面一篇 PHP递归实现文件夹的复制
- 问题描述:报错信息:Caused by: com.mysql.jdbc.PacketTooBigException: Packet for
- vue通过路由传值在许多跳转的同时需要完成携带参数,并且在刷新的同时不丢失参数。$router:是路由操作对象,只写对象$route:路由信
- 复数是由一个实数和一个虚数组合构成,表示为:x+yj一个复数时一对有序浮点数(x,y),其中x是实数部分,y是虚数部分。Python语言中有
- pip简介pip 是一个现代的,通用的 Python 包管理工具。提供了对 Python 包的查找、下载、安装、卸载的功能pip是官方推荐的
- 一、Tesseract-OCR 是什么An OCR Engine that was developed at HP Labs between