1.async的使用
async修饰的函数默认返回都是promise对象
async function test(){
console.log('111')
return 222
// 如果是原始类型的值,会转换为resolve的promise对象
}
// 以上代码等价于
function test(){
console.log('111')
return new Promise(resolve => {
resolve(222)
}
}
2.await
await必须出现在async修饰的函数中,且await写在表达式的前面,表达式的返回值是一个promise对象,如果不是,会通过Promis.resolve() 转化为promise对象
async function test() {
return "1111";
}
async function demo() {
console.log(await test());
}
demo();
// 上下代码等效
function test() {
return new Promise((resolve, reject) => {
console.log('2222')
resolve("1111")
})
}
function demo() {
return new Promise((resolve, reject) => {
test().then(res => {
console.log(res) // .then为微任务,会加入到微任务队列中,直到主任务执行完
// 才会执行微任务队列,但test()为同步任务
})
})
}
demo();
// 运行结果 : 2222 1111
function test() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('2222')
})
resolve("1111")
})
}
function demo() {
return new Promise((resolve, reject) => {
test().then(res => {
console.log(res) // .then为微任务,会加入到微任务队列中,直到主任务执行完
// 才会执行微任务队列,但test()为同步任务
})
})
}
demo();
// 运行结果 1111 2222 因为setTimeout为宏任务队列,所以微任务队列先执行
async的出现有时候可以让我们省略new Promise,直接return,但有些时候还是不能省略的,比如我们需要在setTimeout这种回调函数去return,然后来改变promise状态,但这是行不通的
async function test(){
console.log('开始')
setTimeout(() => {
return '返回promise'
})
}
async function demo(){
let res = await test()
console.log(res)
}
demo()
// 运行结果 开始 undefined
// 默认返回的是undefined
因此,我们只能new Promise对象来改变promise状态
async function test(){
return new Promise((resolve,reject) => {
console.log('开始')
resolve('返回promise')
})
}
async function demo(){
let res = await test()
console.log(res)
}
demo()
// 运行结果 开始 返回promise
await只能是捕获成功的回调,这时候我们可以使用try...catch 来捕获失败的
方法一:
async function test(flag){
if(flag){
throw new Error('出错了')
}else{
return '666'
}
}
async function demo(){
try{
let res = await test(false)
console.log(res)
await test(true)
}catch(e){
console.log(e)
}
console.log('出错了我还能执行') // 加了try..catch即使异步抛出错误,也不会影响后续执行
}
demo()
// 运行结果
666
Error: 出错了
at test (<anonymous>:3:15)
at demo (<anonymous>:13:15)
出错了我还能执行
方法二:
async function test(flag){
if(flag){
throw new Error('出错了')
}else{
return '666'
}
}
async function demo(){
await test(true).catch(e => {
console.log(e)
})
console.log('出错了我还能执行') // 加了catch就不会影响后续的执行
}
demo()
运行结果如下:
Error: 出错了
at test (<anonymous>:3:15)
at demo (<anonymous>:13:15)
出错了我还能执行
多个await
命令后面的异步操作,因为他们需要等待上一步的完成,所以并不是同时触发的,会比较浪费时间,如
async function test(num){
return new Promise(resolve => {
setTimeout(() => {
resolve(num * 2)
},2000)
})
}
async function demo(){
let one = await test(10)
let two = await test(20)
let three = await test(30)
console.log(one + two + three)
}
demo()
// 经历大约6秒的时间,打印出120
// 但以上几个await我们并需要他们可以同时触发,这样节约运行的时间
解决需要同时触发的多个await异步事件
方法一:
async function test(num){
return new Promise(resolve => {
setTimeout(() => {
resolve(num * 2)
},2000)
})
}
async function demo(){
// 使用promise.all 这样就可以使多个await异步事件同时触发
let [one,two,three] = await Promise.all([test(10),test(20),test(30)])
console.log(one + two + three)
}
demo()
// 大概经历2秒,打印出120
方法二:
async function test(num){
return new Promise(resolve => {
setTimeout(() => {
resolve(num * 2)
},2000)
})
}
async function demo(){
let one1 = test(10) // 没有加await就同时执行,不会停止
let two2 = test(20) // 前面3个会同时执行,且new Promise是同步任务
let three3 = test(30) // 因为setTimeout是宏任务,所以会放进队列中,
// 最后队列中await的时间间隔都是0秒了,相当于在队列中把那两秒都消耗完了
let one = await one1
let two = await two2
let three = await three3
console.log(one + two + three)
}
demo()
// 大概经历2秒,最后打印出120
以上的多个setTimeout宏任务加入队列,相当于如下代码
// 需求是希望间隔打印出 0 - 4
let time = 0;
for(let i = 0;i < 5;i++){
setTimeout(() => {
time += 500;
console.log(i,time)
},time)
}
// 以上最后运行出来是同时打印出来 0 - 4
// 原因: setTimeout为异步任务,于是5个setTimeout都被放入了任务队列,
// 就相当于时间间隔都在任务队列中变为了0,于是当主任务执行完,就执行了异步任务
// 直接就输出了 0-4
// 使用递归就可以实现间隔的打印
function f(time) {
if(time > 2500) {
return ;
}else{
setTimeout(() => {
time += 500;
console.log(time);
f(time);
},time)
}
}
f(0)
最后看一下这段代码的运行
async function async1 () {
console.log('nc1 start') // 这也是同步任务
await async2()
console.log('nc1 end') // 这里相当于写在.then里面的代码,会放入微任务队列里面
}
async function async2 () {
console.log('nc2') // 这也是同步任务
}
console.log('start')
async1()
console.log('end') // 这里是同步任务,会先执行
// 运行结果
start
nc1 start
nc2
end
nc1 end