简单聊一聊「前端异步编程」的实现方式
Posted 木星记note
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简单聊一聊「前端异步编程」的实现方式相关的知识,希望对你有一定的参考价值。
——本文借鉴于阮一峰老师的「es6标准入门(第3版)」
前言:
一直以忙为借口,偷懒了一年
最近刚巧团队内在推广技术氛围,硬性要求每两周更新一篇技术博文
于是乎,以此为契机,我会重拾更文哈
之后的文章更多地会跟技术有关,看不懂又有兴趣的同学欢迎了解一下「前端开发」
好了,废话不多说,让我们开始正文吧
在之前,常用异步编程的方式大概有下面4种
1、回调函数
2、事件监听
3、发布/订阅
4、Promise 对象
首先介绍下第一位嘉宾——回调函数。
所谓回调函数,就是把任务的第二段单独写在一个函数里,等到重新执行这个任务时便直接调用这个函数。
下面举一个最常见的发起请求的例子
a.request({
url: '/test',
data: {}
}, function(){
console.log('我就是回调函数');
});
现在看来这个回调函数没什么问题,那如果有一个业务场景是要按顺序请求多次呢?
看下面这个例子
a.request({
url: '/test1',
data: data1
}, function(){
a.request({
url: '/test2',
data: data2
}, function(){
a.request({
url: '/test3',
data: data3
}, function(){
// ...
});
});
});
这里request方法封装了一个jquery的$.ajax发起请求方法,回调函数在其成功回调里执行
不难想象,如果有多次请求,就会出现多重嵌套。
此时代码不是纵向发展,而是横向发展,很快就会乱成一团,无法管理。这种情况就被称为“回调函数地狱“(callback hell)。
此时,介绍下第二位嘉宾——Promise
Promise对象就是为了解决callback hell而被提出的。
它是一种新的写法,允许将回调函数的嵌套改写成链式调用。
继续上面的例子,如果改成Promise的写法,就会变成下面这个样子
a.request({
url: '/test1',
data: data1
}).then(function(){
url: '/test2',
data: data2
}).then(function(){
url: '/test3',
data: data3
});
这里request封装了一个用Promise发起请求的方法,返回的是一个Promise对象。
Promise提供then方法加载回调函数,catch方法捕捉执行过程中抛出的错误。
可以看到,Promise的写法只是回调函数的改进,使用then方法以后,异步任务的两段执行更清楚了,除此以外,并无新意。
Promise的最大问题是代码冗余,原来的任务被Promise包装以后,无论什么操作,一眼看上去都是许多then的堆积,原来的语义变得很不清楚。
那么,有没有更好的写法呢?
当当当当,此时第三位嘉宾隆重登场——async
先来看看,使用async再次执行上面的例子
(async function(){
await a.request({
url: '/test1',
data: data1
});
await a.request({
url: '/test2',
data: data2
});
await a.request({
url: '/test3',
data: data3
});
})()
可以看到,async对比之前的写法有以下几个优点
1、更好的语义
async 表示函数里有异步操作
await 表示紧跟在后面的表达式需要等待结果
2、更清晰的流程
将异步写法变成了同步写法,流程管理看上去更清晰
下面简单说一下async的用法
async函数返回一个Promise对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
下面看一个在实际业务中简单使用的例子
//这是一个查询列表及其详情并渲染的过程
let data = {
// 查询参数若干...
};
(async function(){
//第一步,获取同步码
let asyncCode = await getAsyncCode();
//第二步,将asyncCode塞入查询参数里,然后开始真正查询
data.asyncCode = asyncCode;
await queryTrade(data);
//第三步,获取同步状态,并渲染页面表格
let list = await getSyncStatus(asyncCode);
updatePackageList(list);
//第四步,获取包裹详情,并渲染
let detail = await getTradeDetail(list);
updatePackageDetail(detail);
})();
await 后面封装的函数是发起对应请求的方法,updateXXX方法是渲染页面的方法
可以看到,流程管理清晰了许多。
好啦,本次先聊到这里,走过路过,喜欢的朋友点个赞啦,有什么想说的或者补充的,也欢迎踊跃留言。
咱们下期再见。
以上是关于简单聊一聊「前端异步编程」的实现方式的主要内容,如果未能解决你的问题,请参考以下文章