async/await 是 Javascript 的异步流程控制的一种方案,可以在 async 函数里面用同步的写法来实现异步的操作,使用非常方便

async 函数

async 函数不同于 generator 函数和普通函数,总是返回一个 promise 对象(后文用 p 表示),如果 async 函数有返回值,使用p.then来获取,如果 async 函数有抛出错误,使用p.catch来获取

await 表达式

await 会**“暂停”**当前 async 函数的执行,返回 promise 处理的结果,然后继续往下执行

await 只能在 async 函数里面执行

举个栗子

async function getBook(url) {
let book = await rp(url, { json: true });
if (!book) {
throw new Error('No book...');
}
return book;
}
let gb = getBook('https://api.douban.com/v2/book/isbn/9787115299710');
gb.then((res) => {
// return value;
console.log(res);
}).catch((err) => {
// throw error
console.log(err);
});

避免错误使用

在编写代码的时候,使用的是同步的写法,但是其实内部运行还是异步的。举个栗子

function getBook(url) {
console.log(`sending book url is ${url}`);
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('book data');
}, 3000);
});
}
function getMusic(url) {
console.log(`sending music url is ${url}`);
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('music data');
}, 1000);
});
}

上面模拟两个异步请求 getBook 和 getMusic,分别是 3 秒和 1 秒后返回数据

function getBook(url) {
console.log(`sending book url is ${url}`);
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('book data');
}, 3000);
});
}
function getMusic(url) {
console.log(`sending music url is ${url}`);
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('music data');
}, 1000);
});
}

从结果可以看出,从请求到输出耗时 4s 左右,虽然看起来没什么问题,但是还是可以优化的,因为两个接口无相互依赖,所以可以实现并行请求的,减低请求消耗的时间,改为下面这种写法

async function getData() {
let gBook = getBook('https://www.baidu.com');
let gMusic = getMusic('https://tmall.com');
let music = await gMusic;
let book = await gBook;
}

对比两种写法,第一种获取到 book 和 music 所需要的时间是 4s 左右,第二种只需要 3s 左右,减少了 1s 左右的延迟

Promise.all

另外如果要并行请求多个相同 url 的请求,可以使用Promise.all方法来获取结果,例如

async function getBookByIds(ids) {
let books = ids.map(async (id) => {
// await加不加都一样?
return await getBookById(id);
});
Promise.all(books).then((res) => {
console.log(res);
});
}