ES6特性:async异步函数

async函数

简介

async函数是使用async关键字声明的函数。
async函数是AsyncFunction构造函数的实例, 并且其中允许使用await关键字。
async和await关键字让我们可以用一种更简洁的方式写出基于Promise的异步行为,而无需刻意地链式调用promise
await关键字只在async函数内有效。如果在async函数体之外使用它,就会抛出语法错误 SyntaxError 。
async/await的目的为了简化使用基于promise的API时所需的语法。
async/await的行为就好像搭配使用了生成器和promise。

async函数介绍

async函数会返回一个promise对象
promise对象的结果由async函数执行的返回值决定
如果一个async函数的返回值看起来不是promise,那么它将会被隐式地包装在一个promise中。
如果async函数的返回值是promise对象,那么async函数的返回值就是这个promise对象的成功或失败的值决定。
如果async函数抛出错误,那么返回结果就是一个失败的promise对象

如下代码:

//async函数返回一个 Promise 对象。
async function foo() {
   return 1;
   
   // 出错就抛出错误,返回结果是一个失败的promise对象
   // throw new Error('出错了!');
}

等价于:

function foo() {
   return Promise.resolve(1)
}

await表达式

1、await 必须写在async函数中
2、await右侧的表达式一般为promise对象
3、await返回的是promise成功的值
4、await的promise失败就会抛出异常,需通过try。。。catch捕获。

如果await返回的是promise成功的值,

<body>
    <script>
        // 创建一个promise对象
        const p = new Promise((resolve, reject) => {
            resolve("用户数据");
        })

        // async函数结合await使用
        async function main(){
            // await关键字后面接promise对象,并且await返回的是promise成功的值
            let result = await p;
            console.log(result);
        }

        // 调用函数
        main(); // 结果:用户数据
    </script>
</body>

如果await返回的是promise失败的值,则需要使用try…catch捕获

<body>
    <script>
        // 创建一个promise对象
        const p = new Promise((resolve, reject) => {
            // resolve("用户数据");
            reject("失败了!")
        })

        // async函数结合await使用
        async function main(){
            // 使用try catch捕获失败
            try{
                // 如果promise对象失败了,那么try会进行一个捕获,然后放到catch中进行处理
                let result = await p;
                console.log(result);
            }catch(e){
                console.log(e);
            }
        }

        // 调用函数
        main();
    </script>
</body>

异步函数示例:

async function foo() {
   const result1 = await new Promise((resolve) => setTimeout(() => resolve('1')))
   const result2 = await new Promise((resolve) => setTimeout(() => resolve('2')))
}
foo();

async与await结合使用

读取文件

假设同级目录FILE下有三个文件first.txt,second.txt,third.txt。

// CJS模块化导入fs
const fs = require("fs");

// 读取第一个文件
function readFirst(){
    return new Promise((resolve,reject) =>{
        fs.readFile("../FILE/first.txt",(err,data) =>{
            // 失败则返回失败结果
            if(err) reject(err);
            // 成功则返回成功数据
            resolve(data);
        })
    })
}

// 读取第二个文件
function readSecond(){
    return new Promise((resolve,reject) =>{
        fs.readFile("../FILE/second.txt",(err,data) =>{
            // 失败则返回失败结果
            if(err) reject(err);
            // 成功则返回成功数据
            resolve(data);
        })
    })
}

// 读取第三个文件
function readThird(){
    return new Promise((resolve,reject) =>{
        fs.readFile("../FILE/third.txt",(err,data) =>{
            // 失败则返回失败结果
            if(err) reject(err);
            // 成功则返回成功数据
            resolve(data);
        })
    })
}

// 使用async函数实现异步编程
async function main(){
    // 获取first.txt文件内容
    let first = await readFirst();
    // 获取second.txt文件内容
    let second = await readSecond();
    // 获取third.txt文件内容
    let third = await readThird();

    console.log(first.toString());
    console.log(second.toString());
    console.log(third.toString());
}

// 调用async函数
main();

结果:

这是第一个文件
这是第二个文件
这是第三个文件


表面上和同步调用很像,其实是在前一步完成的基础上再去进行下一步操作。

发送ajax请求

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 发送ajax请求,返回值为promise对象
        function sendAJAX(url){
            return new Promise((resolve,reject) => {
                // 创建ajax对象
                const x = new XMLHttpRequest();
                // 初始化
                x.open('get',url);
                // 发送
                x.send();

                x.onreadystatechange = function(){
                    if(x.readyState == 4 && x.status >= 200 && x.status < 300){
                        // 成功
                        resolve(x.response);
                    }else{
                        reject(x.status);
                    }
                }
            })
        }

        // 使用async和await测试
        async function main(){
            let result = await sendAJAX("某个get请求的url");
            console.log(result);
        }

        // 调用
        main();
    </script>
</body>
</html>

  • 异步操作为什么要进行同步化?

希望程序异步执行,就是为了 “跳过” 阻塞,减少时间花销,或者避免回调地狱。关于异步方案, ES6 使用了 基于状态管理的 Promise。与之相反的是,如果需要一系列的异步 “串行”,则需要保证信息/消息的顺序性时,就需要异步操作进行同步化,例如多个ajax的请求需要按照队列返回再依次处理,保证客户端的请求与响应顺序。

如果说 Promise 主要解决的是异步回调问题,那么 async + await 主要解决的就是将异步问题同步化,降低异步编程的认知负担。

  • 如果不存在继发关系的异步操作,如何让他们同时触发
    有如下异步操作
let foo = await getFoo();
let bar = await getBar();

上面代码中,getFoogetBar是两个独立的异步操作(即互不依赖),被写成继发关系。这样比较耗时,因为只有getFoo完成以后,才会执行getBar,完全可以让它们同时触发。

// 写法一
let result = await Promise.all([getFoo(), getBar()]);

// 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;

上面两种写法,getFoogetBar都是同时触发,这样就会缩短程序的执行时间。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值