async
async
声明function是一个异步函数,返回一个promise对象,可以使用then方法添加回调函数。
1、async异步函数的执行流程
默认情况下和普通函数的执行流程是没什么区别的
js
async function foo() {
console.log("foo function start~")
console.log("内部的代码执行1")
console.log("foo function end~")
}
console.log("start")
foo()
console.log("end")
// 按顺序输出
// start
// foo function start~
// 内部的代码执行1
// foo function end~
// end
2、async异步函数的返回值
async
函数的返回值一定为promise对象,promise对象的结果由async
函数执行的返回值决定。
2.1、async函数返回值为promise对象
js
async function foo() {}
// 异步函数的返回值一定是一个promise
console.log(foo()) // Promise { undefined }
2.1、async函数返回一个数字
js
async function foo() {
return 123
}
foo().then(res => {
console.log(res) // 输出123
}).catch(err => {
console.log(err)
})
2.2、async函数默认返回
js
async function foo() {}
foo().then(res => {
console.log(res) // 输出'undefined'
}).catch(err => {
console.log(err)
})
2.2、async函数返回一个Promsie对象
js
async function foo() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("hehehehe")
}, 200)
})
}
foo().then(res => {
console.log(res) // 输出'hehehehe'
}).catch(err => {
console.log(err)
})
await
await
操作符只能在async异步函数内部使用。如果一个Promise被传递给一个await
操作符,await
将等待Promise 正常处理完成并返回其处理结果,也就是说它会阻塞后面的代码,等待 Promise对象结果。如果等待的不是Promise 对象,则返回该值本身。
1、await后面跟上一个数字
js
async function foo() {
const res1 = await 123
console.log(res1) // 输出123
}
foo()
2、await后面跟上一个Promsie对象
只有当Promsie的状态变为Fulfilled,后面的代码才会执行。
js
function requestData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('输出')
}, 1000);
})
}
async function foo() {
// 如果没有结果,后面的代码是不会执行的,可以把上面的resolve注释掉试试
const res1 = await requestData()
console.log(res1) // '输出'
console.log("后面的代码1") // '后面的代码1'
}
foo()
3、await后面跟上reject值
如果await
后面的异步操作出错,那么等同于async
函数返回的 Promise对象被reject。后面的代码将不会再执行,我们可以使用try...catch进行包裹防止出错。
js
function requestData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('输出')
}, 1000);
})
}
async function foo() {
try {
const res1 = await requestData() // 这里如果是reject 不会往后执行了
console.log('后续代码')
} catch (error) {
}
}
foo()
async/await的使用场景
在【超简单】一文搞懂Promise的使用一文中,我们谈到在真实的开发场景中,数据的请求一般是异步的,我们常常让接口返回一个Promise对象,以达到在依次请求每个接口的情况下,并保证数据依次输出。比如我现在有个需求:想依次请求接口1,接口2,接口3,并按顺序输出'我喜欢你'。
js
function fn1() {
return new Promise(resolve => {
setTimeout(() => {
resolve('我')
}, 1000)
})
}
function fn2() {
return new Promise(resolve => {
setTimeout(() => {
resolve('喜欢')
}, 200)
})
}
function fn3() {
return new Promise(resolve => {
setTimeout(() => {
resolve('你')
}, 100)
})
}
fn1().then(res => {
console.log(res)
return fn2()
}).then(res => {
console.log(res)
return fn3()
}).then(res => {
console.log(res)
})
// 1s后输出'我', 再过200ms后输出'喜欢',再过100ms后输出'你'
这么做是没问题的,但是如果嵌套的多了,不免有点不雅观,在开发中,为了代码的简洁性,我们也常用async/await
来解决。
js
async function getData() {
let res1 = await fn1()
console.log(res1)
let res2 = await fn2()
console.log(res2)
let res3 = await fn3()
console.log(res3)
}
getData()
// 1s后输出'我', 再过200ms后输出'喜欢',再过100ms后输出'你'
这样写还有以下好处:
1、更加灵活,直观地控制函数什么时候继续执行、暂停执行。 比如我现在有个需求,先请求完接口3,再拿接口3返回的数据,去当做接口4的请求参数。(在拿接口3的数据的后,我们可以做任何的处理,再拿最后的结果去作为接口4的请求参数,这个过程就相当于对函数进行了暂停,执行的操作)
js
function fn4(val) {
return new Promise(resolve => {
setTimeout(() => {
switch(val) {
case 0:
resolve('我喜欢你')
case 1:
resolve('你不喜欢我')
}
})
})
}
async function getData() {
let res1 = await fn3()
res1 = res1 == '我' ? 0 : 1
let res2 = await fn4(res1)
console.log(res2)
}
getData()
// 输出'你不喜欢我'
2、等到所有的结果都有返回值后,才对所有的返回值进行处理。 比如我现在有个需求,我想拿到所有接口的数据,再对数据做一个总的输出。
js
async function getData() {
let res1 = await fn1()
let res2 = await fn2()
let res3 = await fn3()
console.log(res1 + res2 + res3)
}
getData()
// 1.3s后输出'我喜欢你'
总结:
1、async
函数返回的一定是一个Promise对象;
2、await
只能在async
函数中使用,不然会报错;
3、async/await
的使用能使代码看起来更简洁;
4、async/await
的使用更加灵活,直观地控制函数什么时候继续执行、暂停执行;
5、async/await
的使用能更方便地等到所有的结果都有返回值后进行处理;
结语:
笔者写文章的目的主要还是想用简单的语言来讲懂某一个知识点,同时也巩固一下知识。如有错误的地方,还望大佬不吝赐教。如果觉得写得好的,也可以点个赞支持一下。