概述
async和await是ES2016新增的两个关键字,它们借鉴了ES2015中生成器在实际开发中的应用,目的是简化Promise api的使用,并非是替代 Promise。只是一个语法糖。
async
目的是为了简化在函数的返回值中对Promise的创建。
async用于修饰函数(无论是函数字面量还是函数表达式),放置在函数最开始位置,被修饰函数的返回结果一定是Promise对象。
函数字面量: function test(){}
函数表达式:匿名函数或箭头函数
async function test(){
console.log('1');
return 2;
}
// 等效于
function test() {
return new Promise((resolve, reject) => {
console.log('1');
resolve(2);
})
}
// 如何返回reject
async function test(){
console.log('1');
throw 3;
return 2;
}
await
await关键字必须出现在async函数中!!!
await用在某个表达式之前,如果表达式是一个Promise,则得到的是thenable中的状态数据。
async function test1() {
console.log(1);
return 2;
}
async function test2() {
const result = await test1();
console.log(result);
return undefined;
// 等效于
// return new Promise((resolve, reject) => {
// test1().then((data) => {
// const result = data;
// console.log(result);
// resolve();
// });
// });
}
test2();
举例:获取李华所在班级的老师的信息
思路:
1.获取李华的班级id
2.根据班级id获取李华所在班级的老师的id
3.根据老师id查询老师的信息
async function getTeacher() {
// 获取所有的学生
const stus = await ajax({
url: 'students.json'
})
// 等效于
// ajax({
// url: ''
// }).then(resp => {
// const stus = resp;
// })
// 获取李华的班级id
let cid;
for (let i = 0; i < stus.length; i++) {
if (stus[i].name === "李华") {
cid = stus[i].classId;
}
}
// 获取所有的班级
const cls = ajax({
url:'classes.json'
})
// 获取老师的id
let tid;
for (let i = 0; i < cls.length; i++) {
if (cls[i].id === cid) {
tid = cls[i].teacherId;
}
}
// 获取所有老师
const ts = await ajax({
url: "./data/teachers.json"
})
// 获取老师的信息
for (let i = 0; i < ts.length; i++) {
const element = ts[i];
if (element.id === tid) {
console.log(element);
}
}
}
getTeacher();
分析:
- 在async函数里调用ajax
- async函数返回Promise
- 只要返回Promise就可以等待(await)
- 等待resolve之后,就可以获取状态数据
- async里的代码全是放到then里面的
举例:
垦哥心中有三个女神; 有一天,垦哥决定向第一个女神表白,如果女神拒绝,则向第二个女神表白,直到所有的女神都拒绝,或有一个女神同意为止。
用代码模拟上面的场景。
(async () => {
const gods = ["女神1", "女神2", "女神3", "女神4", "女神5"];
for (let i = 0; i < gods.length; i++) {
const g = gods[i];
// 当前循环等待的Promise没有resolve,下一次循环不运行
const result = await biaobai(g);
if(result){
console.log(`${g}同意了,不用再表白了!!!`);
break;
} else {
console.log(`${g}没有同意`)
}
}
})()
function biaobai(god) {
return new Promise(resolve => {
console.log(`垦哥向${god}发出了表白短信`);
setTimeout(() => {
if (Math.random() < 0.3) {
//女神同意拉
resolve(true)
} else {
//resolve
resolve(false);
}
}, 500);
})
}
特殊场景
场景一:
如果await的表达式不是Promise,则会将其使用Promise.resolve包装后按照规则运行。
async function test() {
const result = await 1;
console.log(result)
}
// 等效于
function test() {
return new Promise((resolve, reject) => {
Promise.resolve(1).then(data => {
const result = data;
resolve();
})
})
}
test();
console.log(123);
场景二:
await 错误的情况
async function getPromise() {
if (Math.random() < 0.5) {
return 1;
} else {
throw 2;
}
}
async function test() {
// 等效于
// getPromise().then(data => {
// const result = await getPromise();
// console.log('正常状态', result)
// }, error => {
// console.log('错误状态', error)
// })
try {
const result = await getPromise();
console.log('正常状态', result)
} catch (error) {
console.log('错误状态', error)
}
}
test();
改造计时器
function delay(duration) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, duration)
})
}
async function biaobai(god){
console.log(`垦哥向${god}发出了表白短信`);
await delay(500);
return Math.random() < 0.3
}