第七章 async 与 await

1 async 函数

用法:

在函数声明的前面加上async关键字,就变成了 async 函数。

async function f() {
  return 'hello world';
}

返回值:

async 函数的返回值是一个 Promise 实例,Promise 实例的结果由 async 函数的返回值决定:

① 如果返回的是一个 Promise 实例,最终得到的 Promise 对象的状态与值与返回的 Promise 实例保持一致。

② 如果返回的是一个非 Promise 实例的值,async 函数返回的一个状态为 resolved 的 Promise 实例,value 是函数内返回的值。

③ 如果没有返回值,async 函数返回一个状态为 resolved 的 Promise 实例,value 是 undefined。

④ 如果抛出错误,async 函数返回一个状态为 rejected 的 Promise 实例,reason 是抛出的错误。

2 await 表达式

async function main(){
    let result = await Promise.resolve('hello world');
    console.log(result);  // hello world
};
main();

async function f(){
    let result = await 998;
    console.log(result);  // 998
}
f();

async function foo(){
    let result = await {
        then(resolve, reject){
            setTimeout(() => {
                resolve('success')
            }, 2000);
        }
    };
    console.log(result);  // success
}
foo();

规则:

① await 表达式必须写在 async 函数的里面。但async函数中可以没有 await,不过一般二者是一起使用的。

② await 表达式可以取到 Promise 实例的结果(就是状态发生改变后传到回调函数的值)。当然,必须等到 Promise 实例的状态发生变化,await 表达式才能取到值。

关于 await 的右侧的表达式:

① 一般为 Promise 实例,await 表达式的值就是该 Promise 实例的结果。

② 如果是个其他类型的值(非 Promise 类型),await 表达式的值就是这个值。

③ 后面是一个 thenable 对象(即定义then方法的对象),那么会将其等同于 Promise 对象。(介绍 Promise.resolve() 方法的时候介绍过 thenable 对象)

注意:

如果 await 右侧的是个状态为失败的 Promise 实例,会抛出异常。我们建议将 await 表达式放在try...catch结构里面。

async function f() {
  try {
    await Promise.reject('出错了');
  } catch(e) {
  }
  return await Promise.resolve('hello world');
}

总结:

async/await 可以直接拿到 Promise 的结果,可以代替 then() 方法和回调函数。可以取代链式调用,是回调地狱的终极解决方案。

缺点是状态为 rejected 的 Promise 实例,会抛出异常,所以需要写在 try...catch结构中防止出错。

3 案例

3.1 async/await 发送 Ajax 请求

function sendAjax(url){
    return new Promise((resolve, reject) => {
        let xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(){
            if (xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                    resolve(xhr.responseText);
                } else {
                    reject(xhr.status);
                }
            }
        };
        xhr.open("GET", url);
        xhr.send();
    })   
}

async function main(){
    try {
        let result = await sendAjax('https://api.apiopen.top/getAllUrl')
        console.log(JSON.parse(result));
    } catch(err) {
        console.log('请求失败',err);
    }
}
main();

3.2 async/await 代替链式调用

我们实现按照顺序读取3个文件的内容。

// 导入模块
const util = require('util');
const fs = require('fs');

// 使用 util 的方法得到一个返回 Promise 实例的方法
const readFile = util.promisify(fs.readFile);

//连续读取三个文件 按照顺序
async function main(){
    try {
        let data1 = await readFile('../content1.txt');
        let data2 = await readFile('../content2.txt');
        let data3 = await readFile('../content3.txt');
        console.log(data1, data2, data3)
    } catch (err) {
        console.log(err);
    }
}

// 调用函数
main();

results matching ""

    No results matching ""