async await 它是基于promise的,为什么es6新增了这个?为了解决大量复杂不易读的Promise异步的问题才出现的,首先async await是有密切联系的!下面分别来介绍下它们的之前的关系!
1、async
async必须声明的是一个function!
async test= function () {
return "我是个promise返回值"
};
//语法错误 async必须声明的是一个function
async 是“异步”的意思,所以应该很好理解 async 用于申明一个 异步的function,返回的是一个Promise对象!
async function test() {
return "我是个promise返回值" // return Promise.resolve("我是个promise返回值")
}
test();
// Promise {<fulfilled>: "我是个promise返回值"}
返回的是一个promise,不过可以理解为一个状态为fulfilled并且已经拿到了返回值为"我是个promise返回值"的promise 或者可以理解为return Promise.resolve(“我是个promise返回值”),同理如果没有返回值也是Promise.resolve(underfind),下面我们来验证下,后面接个回调函数!
async function test() {
return "我是个promise返回值"
}
test().then((response) => {
console.log(response); //我是个promise返回值
})
是这样的!那么对待async要像对待Promise一样去对待async的返回值!(有点绕口,知道这个意思就可以!)下面我们来看下 await
2、await
await必须是在这个async声明的函数内部使用,必须是直系,否则报错!
async function test() {
function test1() {
await 111;
};
};
//Uncaught SyntaxError: await is only valid in async function
阮一峰老师说:async 函数返回一个 Promise 对象,当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句。
是这样吗?我们来测试下!
async function test() {
await setTimeout(() => {
console.log("我是不是最开始执行")
}, 1000);
console.log('我什么时候执行');
}
test();
//我什么时候执行
// 1s之后 我是不是最开始执行
我擦?不对啊! 怎么下面先开始执行了? 这里是有条件的,如果await后面是 promise对象,会将promise异步操作转为同步,等待 promise的resolve/reject 返回结果.,再接着执行函数体内后面的语句!
继续测试下!
async function test() {
await new Promise((resolve, reject) => {
setTimeout(() => {
console.log("我是不是最开始执行")
}, 1000);
});
console.log('我什么时候执行');
}
test();//我是不是最开始执行
怎么又不对?为什么下面 console.log(‘我什么时候执行’)没执行,是不是哪里写错了?原来是如果await的是一个promise对象,那么要等待这个对象解析完成,如果没有resolve或者reject那么后面的内容就不会执行!
再改下!
async function test() {
await new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
console.log("我是不是最开始执行")
}, 1000);
});
console.log('我什么时候执行');
}
test(); // 1s之后 我是不是最开始执行 我什么时候执行
和阮老师说的貌似一致了!那么得出一个结论!如果await后面如果不是一个promise对象那么它就按正常的js顺序执行,先执行同步代码,当主线程空闲了,再去执行异步队列的任务!既然说到了这里,那么再讲深入一点点!js的执行机制大家应该知道!宏任务和微任务等(不懂的可以点击这里),看下面的一道面试题!
async function test() {
console.log("async1");
await new Promise((resolve, reject) => {
resolve(1)
});
console.log('async2');
};
setTimeout(function () {
console.log("setTimeout");
}, 0);
test();
new Promise(function (resolve) {
console.log("promise1");
resolve();
}).then(function () {
console.log("promise2");
});
console.log('end');
相信很多人都会做错,那么我们来分析下!
- 执行第一轮宏任务,发现setTimeout是个宏任务,0秒后直接扔到宏任务异步队列!
- 执行test(),先输出"async1",直接执行await,因为后面是个promise对象,所以会"阻塞"后面的任务,直到拿到1这个结果,这里是重点
发现console.log('async2')是个微任务,扔进微任务异步队列,执行完await后面的promise,那么后面的代码都是在promise.then()里面执行,所以console.log('async2')是个微任务!
- 执行new Promise,执行同步代码输出"promise1", then后面又是个微任务,扔进任务异步队列!
- 执行同步代码输出’end’!
- 一轮宏任务执行完毕,看下有没有微任务,执行第一个微任务输出’async2’,再执行第二个微任务"promise2",微任务执行结束,再执行第二轮宏任务!
- 最后执行宏任务输出"setTimeout"
- 所以执行结果是"async1",“promise1”,‘end’,‘async2’,“promise2”,“setTimeout”
上面说的偏题了,主要想说的是await后面如果不是一个promise对象那么它就是按正常js执行顺序(先同步后异步),是promise对象那么await后面的内容还是相当于在then执行,跟promise的区别在于如果等待的是一个promise对象,那么要等待这个对象解析完成,如果没有resolve或者reject那么后面的内容就不会执行
async function test() {
console.log("async1");
await new Promise((resolve, reject) => {
resolve()
});
console.log('async2');
};
//等价于
async function test() {
console.log("async1");
await new Promise((resolve, reject) => {
resolve()
}).then(() => console.log('async2'));
};
async function fn2() {
await 2
console.log(2)
}
//等价于
async function fn2() {
Promise.resolve(2).then(() => console.log(2))
}
接着正题说,那么await有返回值吗?返回值是什么?
async function test() {
let result = await new Promise((resolve, reject) => {
setTimeout(() => {
resolve('返回的值');
}, 1000);
});
console.log(result) //返回的值
// 等价于Promise.resolve(result).then(() => console.log(result));
return result;
};
test().then((data) =>
console.log(data)//返回的值
)
看上面的例子可以发现await 的返回值就是promise的resolve/reject 返回结果,然后通过执行async函数 retrun出来,相当于 Promise.resolve("返回结果")!
当async函数抛出异常时或者await 的返回值reject状态 ,Promise 的 reject 方法也会传递这个异常值!
async function test() {
throw Error("获取错误")
};
test().catch((error) =>
console.log(error)
);
//Error: 获取错误
async function test() {
let result = await new Promise((resolve, reject) => {
setTimeout(() => {
reject("获取返回值失败");
}, 1000);
});
console.log(result) //失败后后面代码不执行了
return result;
};
test().catch((error) =>
console.log(error)//获取返回值失败
);
3、async await 和promise相比的优势
async await是promise的进化版,async await 相比原来的Promise的优势在于处理 then链,不必把回调嵌套在then中,只要await 即可
我们来模拟下一个场景,有3个请求,但是有顺序的,必须要先执行第一个,再执行第二个,最后执行第三个,并且1秒后执行第一个请求,执行完第一个请求后,3秒后执行第二个请求,执行完第二个请求后,5秒后执行第三个请求!平时工作中应该很多这种需求!
promise会这样写
let request1 = (time) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('request1返回的值');
}, time * 1000);
});
};
let request2 = (time) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('request2返回的值');
}, time * 1000);
});
};
let request3 = (time) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('request3返回的值');
}, time * 1000);
});
};
request1(1).then((data) => {
console.log(data);//request1返回的值
return request2(3)
}).then((data) => {
console.log(data);//request3返回的值
return request3(5)
}).then((data) => {
console.log(data)//request3返回的值
})
async await 会这样写
async function request() {
let resolve1 = await request1(1);
console.log(resolve1);
resolve2 = await request2(3);
console.log(resolve2);
resolve3 = await request3(5);
console.log(resolve3);
}
request();
是不是没有冗余的长长的链式代码,语义化也非常清楚,看起来很舒服!,本来想把async await 如何捕获异常也写了,想不想还是下篇再补完吧!