异步编程解救指南

775 4 技术 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.allPromise.race的方法,对于并发请求的处理提供了高效的方案。

ES7给出的终极方案

上面ES6给出的Promise方案说到底还是回调的形式,只不过是链式回调,在异步编程中并不是最完美的。终极的方案应该是使同步异步代码统一,即是让异步的代码变成和同步代码一样书写。ES7提出的asyncawait则能够彻底解决回调地狱问题。

通过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状态被改变才会通过=号赋值给变量,然后继续往下面执行,在语法上就和同步代码是一样的了。

这个方案是最被推荐的,目前兼容性还不佳,但是在前端领域的未来几年内一定会成为主流方案。

© 2020 peal.cc 粤ICP备2020133024号