{
    分享网正式开通,我们为大家提供免费资源,欢迎大家踊跃投稿!

为什么要使用 async/await ?

async/await 是 ES7 的标准,Promise 是 ES6 标准,async/await 这套 API 也是用来帮助我们写异步代码的,它是构建在 Promise 之上的,有点像 Okhttp 和 Retrofit 的关系。

什么是 async ?


async function myFirstAsyncFunction() {
    try {
        const fulfilledValue = await doSomeThing();
    }
    catch (rejectedValue) {
        // …
    }
}
 

大概长上面这个样子。async 一般不单独使用,而是和 await 一起使用,一个 async 函数内部可能有 零个 或者 多个 await 。

这段代码即使没有学过 Promise 也很容易看懂。这就是 async 函数的优势所在。

async 函数被调用的时候,会立即返回一个 Promise。

await

await 不能单独使用,如果在非 async 函数内部被调用会报错。await 后面一般跟一个 Promise ,也可以是其他的,比如一个数值,或者一个变量,或者一个函数。如果 await 后面不是一个 Promise 就会返回一个已经 resolve 的 Promise。

当 async 函数执行到 await 的时候,会暂停整个async函数的执行进程并出让其控制权,只有当其等待的基于Promise 的异步操作被兑现或被拒绝之后才会恢复进程。

当然,async 函数也会返回一个 Promise ,也就是说,await 后面也可以跟一个 async 函数。

async/await 这套 API ,感觉有 Kotlin 中的 协程 和 挂起函数 内味。

为什么要使用 async ?

隐藏 Promise ,更易于理解

假设我们想请求一个接口,然后把响应的数据打印出来,并且捕获异常。用 Promise 大概是这样写:


function logFetch(url) {
    return fetch(url)
        .then(response => response.text())
        .then(text => {
            console.log(text);
        }).catch(err => {
            console.error('fetch failed', err);
        });
}
 

如果用 async 函数来写,大概是这个样子:


async function logFetch(url) {
    try {
        const response = await fetch(url);
        console.log(await response.text());
    }
    catch (err) {
        console.log('fetch failed', err);
    }
}
 

虽然代码的行数差不多,但是代码看起来更加简洁,少了很多 then 的嵌套。请求一个接口数据,然后打印,就像你看到的,很简单。

就像刚才的那个例子,如果没学过 Promise 也不影响你看懂和理解 async 代码。这个好像没什么,但是对于一个大型的项目,人员的技术水平参差不齐,不能保证所有人都熟悉和理解 Promise ,我们要做的是尽可能的降低代码的理解难度,使大部分人都能看懂。

用同步的思路写异步逻辑

async/await 最大的优势就是我们可以用同步的思路来写异步的业务逻辑,所以代码整体看起来更加容易看懂。我们举个例子。

上面的代码还是比较简单,我们再举一个复杂一点的例子。

我们想获取一个网络资源的大小,如果使用 Promise 大概可能是这个样子:


function getResponseSize(url) {
    return fetch(url).then(response => {
        const reader = response.body.getReader();
        let total = 0;

        return reader.read().then(function processResult(result) {
            if (result.done) return total;

            const value = result.value;
            total += value.length;
            console.log('Received chunk', value);

            return reader.read().then(processResult);
        })
    });
}
 

即使你学过 Promise ,这个代码也并不是很好理解,更别说是没有学过 Promise 的同学了。因为中间有一个循环的过程,而且这个执行的过程的异步的,并不想我们之前学到的一个链式调用能解决的。当然,你也可以抽取一下,使代码更简洁一点。


const processResult = (result) =>{
            if (result.done) return total;

            const value = result.value;
            total += value.length;
            console.log('Received chunk', value);

            return reader.read().then(processResult);
}

function getResponseSize(url) {
    return fetch(url).then(response => {
        const reader = response.body.getReader();
        let total = 0;

        return reader.read().then(processResult)
    });
}
 

但是多了一个方法,勉勉强强吧。但是我们看一下 async 函数是怎么处理的。


async function getResponseSize(url) {
    const response = await fetch(url);
    const reader = response.body.getReader();
    let result = await reader.read();
    let total = 0;

    while (!result.done) {
        const value = result.value;
        total += value.length;
        console.log('Received chunk', value);
        // get the next result
        result = await reader.read();
    }

    return total;
}
 

这个是不是看起来就更加流畅了?因为 await 表达式会阻塞运行,甚至可以直接阻塞循环,所以整体看起来像同步的代码,也更符合直觉,更容易读懂这个代码。

小心 await 阻塞

由于 await 能够阻塞 async 函数的运行,所以代码看起来更像同步的代码,更容易阅读和理解。但是要小心 await 阻塞,因为有些阻塞是不必要的,不恰当使用可能会影响代码的性能。

假如我们要把一个网络数据和本地数据合并,错误的实例可能是这样子:


async function combineData(url, file) {
        let networkData = await fetch(url)
        let fileData = await readeFile(file)
        console.log(networkData + fileData)
}
 

这样的话,就可以同时 网络请求 和 读取文件 了,可以节省很多时间。这里主要是利用了 Promise 一旦创建就立刻执行的特点,不懂的同学可以复习一下上一节的内容。

当然,如果你熟悉 Promise 的话,可以直接使用 Promise.all 的方式来处理,或者 await 后面跟 Promise.all 这里就不展开讲了。

异常处理

try...catch

在 async 函数中,异常处理一般是 try...catch ,如果没有进行 try...catch ,await 表达式一旦 reject ,async 函数返回的 Promise 就会 reject 。

其实结合 Promise 来看,如果一个 Promise 状态敲定为 reject ,并且后续的 then 没有传入 reject 函数,或者没有 catch ,那么就会抛出异常。从这个角度来看,在 async 函数中用 try...catch 来包住 await 表达式,可能就是 catch 住这个异常,并且把这个 reject 信息传到 catch 里面。

这里就不举例子了。


资源均来自第三方,谨慎下载,前往第三方网站下载


米微资源分享网 , 版权所有丨本站资源仅限于学习研究,严禁从事商业或者非法活动!丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:为什么要使用 async/await ?
喜欢 ()分享 (0)