(1) async关键字用于申明异步函数,可用于箭头函数,函数表达式,function函数声明,方法
const fun = async () => {
console.log(1)
}
async function fun1() {
console.log(2)
}
const o = {
say: async () => {
console.log('say')
}
}
(2) 使用async关键字声明的函数具有异步特征(返回的是一个Promise实例对象,函数内部可以使用await关键字),但总体上其代码还是同步求值的,即函数调用是同步任务
const fun = async () => {
console.log(1)
}
console.log('fun',fun())
console.log(2)
打印结果:
1
fun() Promise { undefined }
2
(3) 异步函数如果使用return关键字返回了值,那么这个值会被Promise.resolve包裹成一个期约对象(即Promise实例对象)
const f = async () => {
return 100
}
console.log(f())
f().then(console.log)
打印结果:
Promise {100}
100
(4) 也可以直接返回一个期约对象
const f1 = async () => {
// return Promise.resolve('这是一个Promise实例对象')
return Promise.reject('这是一个Promise实例对象')
}
f1().catch(console.log) // 这是一个Promise实例对象
(5) 还可以返回一个实现thenable接口的对象(是一个对象,里面有一个then方法,参数是函数),这个then方法将会作为此次Promise.then
async function func() {
return {
then(cb) {
cb('cb')
}
}
}
console.log(func()) // Promise {pending},此时处于初始状态
func().then(console.log) // cb
(6) 可以在异步函数里抛出一个错误会返回一个拒绝的期约对象(reject)
async function err() {
console.log(1)
throw new Error('error') // 相当于return,后面的代码不会执行
console.log(2)
}
err().catch(console.log) // error
(7) 但是,拒绝的期约对象的错误不会被异步函数捕获
async function rej() {
console.log(1)
Promise.reject('error1234')
}
console.log(rej())
打印结果:
1
Promise { undefined }
报错
(1) await可以暂停和恢复异步函数代码的执行,等待期约解决,再 异步 恢复异步函数的执行(即等待拿到结果后,再异步(恢复)执行后面的代码,相当于await语句后面的代码成了一个异步任务 -------- Promise.then() )
const fun = async () => {
console.log(3)
const res = Promise.resolve('123')
console.log(1)
console.log('res', res)
// 这串代码等同于:
// Promise.resolve('123').then(res => {
// console.log(1)
// console.log('res', res)
// })
}
console.log(2)
fun()
打印结果:
2
3
1
res Promise { '123' }
(2) await关键字后面跟Promise实例对象,也可以跟一些常规值
const fun1 = async () => {
console.log(1)
const number = await 10
const string = await '10'
const arr = await [1, 2, 3]
const obj = await {
name: 'dieqi'
}
console.log('number', number)
console.log('string', string)
console.log('arr', arr)
console.log('obj', obj)
}
fun1()
打印结果:
1
number 10
string 10
arr [ 1, 2, 3 ]
obj { name: 'dieqi' }
(3) await 后面抛出一个错误对象,会返回一个拒绝的期约对象,注意:await 后面不能直接跟 thorw 关键词,可以包裹一个立即执行函数
const fun3 = async () => {
console.log(1)
await (() => {
throw 3
})()
}
fun3().catch(console.log)
打印结果:
1
3
(4) await 后面直接跟一个拒绝的期约对象,会直接报错,并终止后面代码的执行
const fun4 = async () => {
await Promise.reject('123')
console.log(1) // 此代码不会被执行
}
console.log(fun4()) // 报错信息
fun4().catch(console.log) // 123
- 只能在异步函数中使用,不能在顶级上下文如script中使用
- await关键字只能在async关键字所在作用域下一级作用域使用
const test = async () => {
console.log(await 10)
// 报错 ftn函数不能使用 await 关键字
const ftn = () => {
console.log(await 100)
}
ftn()
}
test()
(1)
async function foo() {
console.log(await Promise.resolve('3'))
}
async function bar() {
console.log(await '2')
}
async function baz() {
console.log('1')
}
foo()
bar()
baz()
1
3
2
/*
await会暂停async函数代码的执行,等到拿到结果后才会异步恢复async函数代码的执行,并且await会帮我们将记录在哪里暂停了代码的执行
foo(): 遇到await,暂停代码执行,由于是异步恢复代码执行的,所以async函数后面代码语句的执行是一个异步任务(等同于Promise.then这个异步任务),记为 then1
此时异步任务队列里面存放 then1 异步任务
bar(): 同 foo(),记为 then2,此时异步任务队列里面 存放 then1(先进来的) then2(后进来的)
baz(): async函数里面不包含 await 关键字,跟普通函数没什么区别,是个同步任务,所以打印 1
接着开始执行 异步任务队列里面的异步任务,所以此时执行 then1,await恢复代码的执行,打印3
接着 then2,打印2
可以这样理解:
const res = await Promise.reslove(10)
consose.log(res)
等同于
Promise.reslove(10).then(res => {
consose.log(res)
})
*/
(2)
async function foo() {
console.log(2)
console.log(await Promise.resolve(8))
console.log(9)
}
async function bar() {
console.log(4)
console.log(await 6)
console.log(7)
}
console.log(1)
foo()
console.log(3)
bar()
console.log(5)
// 1 2 3 4 5 8 9 6 7
(3) 实现延迟等待函数
// 实现延迟函数
const sleep = (time) => {
return new Promise((reslove,reject) => {
setTimeout(reslove, time)
})
}
const test = async () => {
const now = Date.now()
await sleep(2000)
console.log(Date.now()-now)
}
test() // 约等于 2000
(4)实现并行执行
const sleep = (time, i = undefined) => {
return new Promise((reslove, reject) => {
setTimeout(() => {
console.log(time, '第' + i + '元素')
i !== undefined && reslove(i)
}, time)
})
}
// 多个await只会依据顺序执行(串行执行)(代码从上往下执行),即使你们之间没有依赖,
// 但这种情况比较耗时,下一个 await 需要等待上一个 await拿到结果(即执行 resolve或reject函数)
const test = async () => {
const now = Date.now()
await sleep(0)
await sleep(500)
await sleep(1000)
await sleep(1500)
console.log(Date.now() - now) // 约等于 3000
}
test()
对上面的代码改进实现平行执行函数
- 在每一个 await 关键词外面包裹一个定时器(延迟0ms),这样就将多个 await 给分割开了,两两之间就不会有影响了
const testImprove = async () => {
const now = Date.now()
setTimeout(async () => {
await sleep(0)
}, 0)
setTimeout(async () => {
await sleep(500)
}, 0)
setTimeout(async () => {
await sleep(1000)
}, 0)
setTimeout(async () => {
await sleep(1500)
console.log(Date.now() - now) // 约等于 1500
}, 0)
}
// testImprove()
- 先一次性初始化所有Promise实例对象,然后在分别等待它们的结果
// 2. 先一次性初始化所有Promise实例对象,然后在分别等待它们的结果
// why??
// 理解:在初始化的时候就已经将sleep函数里面的异步任务(setTimeout)注册到异步任务的任务队里里面了,
// 等待满足执行的条件(0 500ms 1000ms 1500ms)就会执行setTimeout
// 初始化的时候setTimeout已经开始计时(在遇到await之前)
// 例:当过了 1000ms 后,此时前三个setTimeout已经满足条件了,此时前三个setTimeout打印出 0 500 1000
// 再执行 await p 的时候就不需要在注册异步任务了,只需等待结果即可
const foo = async () => {
const now = Date.now()
const p1 = sleep(0)
const p2 = sleep(500)
const p3 = sleep(1000)
const p4 = sleep(1500)
await p1
await p2
await p3
await p4
console.log(Date.now() - now) // 约等于 1500
}
// foo()