async-await让你的异步代码更加优雅

本文介绍了async-await的使用,包括它与Promise的关系、基本语法、async关键字、await关键字以及如何实现sleep()函数。通过示例展示了如何通过async-await简化异步代码,强调了不要滥用async-await以及await必须在async函数中的原则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先对于Promise不太熟悉的朋友建议可以先看一下我的这两篇关于Promise的文章

Promise用法详解一

Promise用法详解二

async-await和Promise的关系


async-await是promise和generator的语法糖。只是为了让我们书写代码时更加流畅,当然也增强了代码的可读性。简单来说:async-await 是建立在 promise机制之上的,并不能取代其地位。async和await最关键的用途是以同步的写法实现了异步调用。
 

基本语法

async function fn() {
    let result = await Math.random();
    console.log(result);// 0.10492893687819915
}
console.log(fn());// Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: undefined}


上述代码就是async-await的基本使用形式。有两个陌生的关键字async、await,同时函数执行结果返回了一个promise对象,这样一看似乎并没有什么特别之处。

 async


async用来表示函数是异步的,定义的函数会返回一个promise对象,可以使用then方法添加回调函数。

async function fn1() {
    return 666;
}
fn1().then(val => {
    console.log(val);// 666
});


若 async 定义的函数有返回值,return 666;相当于Promise.resolve(666),没有声明式的 return则相当于执行了Promise.resolve();

await


await 可以理解为是 async wait 的简写。await 必须出现在 async 函数内部,不能单独使用。

function badFn() {
    await Math.random();
}
badFn();// Uncaught SyntaxError: await is only valid in async function


await 后面可以跟任何的JS 表达式。虽然说 await 可以跟很多类型的东西,但是它最主要的意图是用来等待 Promise 对象的状态被 resolved。如果await的是 promise对象会造成异步函数停止执行并且等待 promise 的解决,如果等的是正常的表达式则立即执行。
 我们可以利用这一特性来实现一个sleep函数


 async-await 实现 sleep()函数

  function sleep(ms) {
        return new Promise(
            (resolve) => setTimeout(resolve, ms)
        );
    }
    async function test() {
        var temple = await sleep(1000);
        console.log(1111)
        return temple
    }
    test();
    //延迟1000ms输出了1111


 需求:此时我们有一个简单的需求,需要去依次去读取一些文件的内容。若用 ES5实现会有3层的回调,若用Promise 实现至少需要3个then。一个是代码横向发展,另一个是纵向发展。这里用async-await实现

const fs = require('fs')
function getFileByPath(fpath) {
    return new Promise(function (resolve, reject) {
        fs.readFile(fpath, 'utf-8', (err, dataStr) => {
            if (err) return reject(err)
            resolve(dataStr)
       })
   })
}

async function test() {
    let res1 = await getFileByPath('./1.txt');
    console.log(res1)
    let res2 = await getFileByPath('./2.txt');
    console.log(res2)
    let res3 = await getFileByPath('./3.txt');
    console.log(res3)
}
test()


运行,此时控制台依次输出文件一到三的内容。回看test函数,以同步的方式去书写异步逻辑,简直不要太爽。


不要滥用async-await


要选择合适的场景,还是那上面读取文件的例子来说,我还是需要读取三个文件,相互没有关联,只是需要三个文件全部读取完毕后提示即可。
此时你可能会说上面的可以实现需求啊。的确,不过此时就将异步的并发请求变成了阻塞式同步的操作了。严重影响效率,此时应该这样写。

async function test() {
    let res1 = getFileByPath('./1.txt');
    console.log(res1)
    let res2 = getFileByPath('./2.txt');
    console.log(res2)
    let res3 = getFileByPath('./3.txt');
    console.log(res3)
    await Promise.all([res1, res2, res3]);
    console.log('文件读取完成')
}



async-await只是promise的语法糖,还是需要用promise来实现。

 await必须在async函数上下文中

async function forBugDemo() {
    let arr = [1, 2, 3, 4, 5];
    arr.forEach(item => {
        await console.log(item);
    });
}
forBugDemo();// Uncaught SyntaxError: await is only valid in async function


如上await并未在async函数上下文中故报错。。


 正确写法如下

async function forDemo() {
    let arr = [1, 2, 3, 4, 5];
    for (let i = 0; i < arr.length; i ++) {
        await console.log(arr[i]);
    }
}
forDemo();

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值