第七章 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();