async、await
异步函数写法
async关键字用于声明一个异步函数:
- async是asynchronous单词的缩写,异步、非同步;
- sync是synchronous单词的缩写,同步、同时;
async异步函数和普通函数一样可以有很多中写法:
// 1.最常用的方式
async function foo1() {}
// 2.表达式定义异步函数
const foo2 = async function() {}
// 3.箭头函数定义异步函数
const foo3 = async () => {}
// 4.类中定义异步函数
class Person {
async foo() {}
}
异步函数返回值
异步函数的内部代码执行过程和普通的函数是一致的,默认情况下也是会被同步执行。
异步函数有返回值时,和普通函数会有区别(异步函数返回的是一个Promise):
-
情况一:异步函数有普通的返回值时,异步函数的返回值相当于被包裹到Promise.resolve中;
async function foo() { return 321 // 相当于Promise.resolve(321) } foo().then(res => { console.log(res) // 321 })
-
情况二:如果我们的异步函数的返回值是Promise,状态由会由Promise决定;
const promise = new Promise((resolve, reject) => { setTimeout(() => { resolve(["aaa", "bbb", "ccc"]) }, 3000) }) async function foo() { return promise } foo().then(res => { console.log(res) // 延迟三秒打印['aaa', 'bbb', 'ccc'] })
-
情况三:如果我们的异步函数的返回值是一个对象并且实现了thenable,那么会由对象的then方法来决定;
async function foo() { return { then: function(resolve, reject) { setTimeout(() => { resolve("aaa") }, 3000) } } } foo().then(res => { console.log(res) // 延迟三秒打印 aaa })
异步函数的异常
什么情况下, 异步函数是已拒绝 (rejected) 状态
-
异步函数返回一个Promise主动调用reject会变成rejected状态
async function foo() { return new Promise((resolve, reject) => { reject("err rejected") }) } foo().then(res => { console.log("res:", res) }).catch(err => { console.log("err:", err) // err: err rejected })
-
如果我们在async中抛出了异常,那么程序它并不会像普通函数一样报错,而是会作为Promise的reject来传递;
async function foo() { // 抛出一个异常 throw new Error("my async funtion error") return "aaa" } foo().then(res => { console.log("res:", res) }).catch(err => { // catch会捕获异常 console.log("err:", err) // err: Error: my async funtion error })
await关键字
async函数另外一个特殊之处就是可以在它内部使用await关键字,而普通函数中是不可以的。
await关键字有什么特点呢?
-
通常使用await是后面会跟上一个表达式,这个表达式会返回一个Promise;
-
那么await会等到Promise的状态变成fulfilled状态,之后继续执行异步函数;
-
await后面表达的结果如果是fulfilled状态, 那么await会将Promise的resolve结果返回
function bar() { console.log("bar函数") return new Promise((resolve, reject) => { setTimeout(() => { resolve(123) }, 3000) }) } async function foo() { console.log("await关键字前面的代码") // await后续跟一个表达式, 表达式返回一个Promise时, 会等待Promise有结果后, 将resolve的结果返回, 继续执行后续代码 const res = await bar() console.log(res) console.log("await关键字后面的代码") } foo() // 打印结果 // 1. 直接打印 // await关键字前面的代码 // bar函数 // 2. 等待三秒再打印 // 123 // await关键字后面的代码
如果await后面是一个普通的值,那么会直接返回这个值;
async function foo() {
console.log("await关键字前面的代码")
const res = await 123
console.log(res)
console.log("await关键字后面的代码")
}
foo()
// 打印结果
// await关键字前面的代码
// 123
// await关键字后面的代码
如果await后面的表达式,返回的Promiseed是reject的状态,那么相当于在异步函数中抛出了一个异常, 我们可以在catch方法中捕获, rejected状态后面的异步函数代码不会执行;
function bar() {
console.log("bar函数")
return new Promise((resolve, reject) => {
setTimeout(() => {
reject("err message")
}, 3000)
})
}
async function foo() {
console.log("await关键字前面的代码")
const res = await bar()
console.log(res)
console.log("await关键字后面的代码")
}
foo().catch(err => {
console.log("err", err)
})
// 打印结果
// 1.直接打印
// await关键字前面的代码
// bar函数
// 2.等待三秒打印
// err err message
如果await后面是一个thenable的对象,那么会根据对象的then方法调用来决定后续的值;
function bar() {
console.log("bar函数")
return {
then: function(resolve, reject) {
resolve("aaa")
}
}
}
async function foo() {
console.log("await关键字前面的代码")
const res = await bar()
console.log(res)
console.log("await关键字后面的代码")
}
foo()
// 打印结果
// await关键字前面的代码
// bar函数
// aaa
// await关键字后面的代码
await处理异步请求
上一篇中, 我们最终是使用生成器处理网络请求, 在学习了await后, 我们可以使用await处理异步请求, 再进一步的优化代码
-
为了方便大家观看, 我将上一篇中的代码拿过来可以回顾一下
// 封装模拟网络请求的函数 function requestData(url) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(url) }, 2000) }) } // 生成器的处理方案 function* getData() { const res1 = yield requestData("why") console.log("res1:", res1) const res2 = yield requestData(res1 + "kobe") console.log("res2:", res2) const res3 = yield requestData(res2 + "james") console.log("res3:", res3) } // 自动化执行生成器函数(了解) function execGenFn(genFn) { // 1.获取对应函数的generator const generator = genFn() // 2.定义一个递归函数 function exec(res) { const result = generator.next(res) if (result.done) return result.value.then(res => { exec(res) }) } // 3.执行递归函数 exec() }
-
我们再使用async函数和await关键字重构上面代码
function requestData(url) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(url) }, 2000); }) } async function getData() { const res1 = await requestData("aaa") console.log("res1:", res1) // aaa const res2 = await requestData(res1 + "bbb") console.log("res2:", res2) // aaabbb const res3 = await requestData(res2 + "ccc") console.log("res3:", res3) // aaabbbccc } // catch用于捕获异常 getData().catch(err => { console.log("err:", err) })
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/120126.html