异步编程解救指南
1058 4 0 技术 2021-02-09
在日常JS编程中,会经常遇到异步逻辑,就是需要等待某条件成立之后再执行的代码,这种情况经常出现在ajax请求中,所以着重用ajax请求作为例子讲解。
回调函数
这是我们用的最多的方法,通过指定一个函数或匿名函数,在异步完成后调用这个回调函数(callback function)。
这种方法在web应用初期逻辑简单情况下其实也够用,例如做一些简单的表单操作和提交。随着web应用的复杂化,弊端也暴露出来,常见的问题就是回调地狱的问题,造成代码杂乱、闭合符混乱,代码写起来极不优雅。 下面用JQ框架中常用的ajax请求为例:
$.get("/test1", function (res1) {
$.get("/test2", function (res2) {
$.get("/test3", function (res3) {
$.get("/test4", function (res4) {
console.log(res4);
});
});
});
});
ES6给出的方案
ES6标准的提出解决了许多以往的不足,针对回调地狱的问题提出的方案是Promise
。通过创建一个Promise
对象,在异步完成之后进行链式回调,与以往相比解决了回调地狱问题,语法也十分优雅。
Axios就是一个基于Promise的请求库,下面用它来举例
axios.get('/test1')
.then(res => { return axios.get('/test2') })
.then(res => { return axios.get('/test3') })
.then(res => { return axios.get('/test4') })
.then(res => { ... })
除了解决回调问题,它还提供了Promise.all
和Promise.race
的方法,对于并发请求的处理提供了高效的方案。
ES7给出的终极方案
上面ES6给出的Promise
方案说到底还是回调的形式,只不过是链式回调,在异步编程中并不是最完美的。终极的方案应该是使同步异步代码统一,即是让异步的代码变成和同步代码一样书写。ES7提出的async
与await
则能够彻底解决回调地狱问题。
通过async
定义一个函数,我们把这个叫做异步函数,这个函数内可以使用await
去等待一个Promise
异步成功,只有当异步成功后才能继续执行下面的代码。
同样是ajax请求的情况,ES7中可以这么写:
(async function () {
const res1 = await axios.get('/test1');
const res2 = await axios.get('/test2');
const res3 = await axios.get('/test3');
const res4 = await axios.get('/test4');
console.log(res1, res2, res3, res4);
})()
说到底这个就是Promise
实现的语法糖,只有当await
后面的Promise
状态被改变才会通过=号赋值给变量,然后继续往下面执行,在语法上就和同步代码是一样的了。
这个方案是最被推荐的,目前兼容性还不佳,但是在前端领域的未来几年内一定会成为主流方案。