概念
async函数是另一种处理异步编程的方法
async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。
通俗理解就是:
调用async 函数返回是promise实例后面可以接then()方法回调函数 ,async函数体内执行任务,遇到await命令会先停止执行,等到异步任务执行完成后再接着执行函数内后面的语句 。
基本用法
async函数多种写法
//函数声明
async function f() {}
//函数表达式
const foo = async function () {}
//对象方法
let obj = {
async foo() {
}
}
obj.foo().then()
//class 方法
class Store {
constructor() {
}
async foo() {
}
}
const store = new Store()
store.foo().then()
//箭头函数
const foo = async () => {}
async函数返回的是promise对象
也可以作为await命令后面的参数 看成async函数的嵌套使用
async function timeout() {
return await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2)
}, 1000)
})
}
async function foo() {
const _res = await timeout()
return _res
}
foo().then(res => console.log(res))
函数内有return 值 状态会变fulfilled,then方法会接收回调函数
如果函数内抛出异常 状态会变rejected,catch方法会接收回调函数
async function f1() {
return 'hello world'
}
f1().then(res => console.log(res))
//hello world
// f1() 状态变为fulfilled
async function f2() {
throw new Error('error')
}
f2().catch(err => console.log(err))
//Error: error
//f2() 状态变为 rejected
async返回的promise状态变化
- 取决于 内部的await命令后面的 promise对象状态变化以及 有无返回值\
- 无return
- return 普通值
- return promise对象
- 中间执行return
//async没有return
async function f7() {
await new Promise((resolve, reject) => {
resolve(123)
})
}
f7().then(res => console.log(res))
//async 函数内没有return值,所有默认函数返回 undefined
//return promise
async function f3() {
const res1 = await new Promise((resolve, reject) => {
resolve(1)
})
console.log(res1)
return new Promise((resolve, reject) => {
resolve(2)
})
//也等同于
// return await new Promise((resolve, reject)=>{resolve(2)})
}
f3().then(res => {
console.log(res)
})
//return 一个promise对象,该promise执行完状态变为fulfilled,接后面的then方法
//输出: 1 2
//return 普通值
async function f4() {
return 123
//等同于
// return await 123
}
f4().then(res => console.log(res))
//return普通值 等同于执行了 await 命令
//输出:123
//中间任务return
async function f5() {
await new Promise((resolve, reject) => {
resolve(1)
})
return 2
await new Promise((resolve, reject) => {
resolve(3)
})
console.log(4)
}
f5().then(res => console.log(res))
//中间执行了return 后面任务不在执行,f5()状态变为fulfilled
//输出:2
利用async await命令 特点演示休眠效果 让程序停顿指定的时间
function sleep(tm) {
return new Promise((resolve, reject) => {
setTimeout(resolve, tm)
})
}
async function f6() {
for (let i = 0; i < 5; i++) {
console.log(i)
await sleep(1000)
}
}
f6()
//分析 先输出 0 然后遇到await命令 等待promise里的延迟任务执行完,再继续循环执行,以此类推
//每隔1秒输出一个数 0 1 2 3 4
中断执行
------以下几种情况await命令后面的任务会中断执行
- await后面promise状态没有执行resolve方法 变为fulfilled
- await语句后面的Promise对象变为rejected状态
- await后面Promise异步任务抛出错误异常 特殊一个:await后面的promise体内有延时任务执行,后续的任务都要等待该异步任务状态变为fulfilled后再执行
//没有状态变化
const asyncFun1 = async function () {
console.log(1)
await new Promise((resolve, reject) => {
}).then(res => console.log(2))
console.log(3)
await new Promise((resolve, reject) => {
reject(4)
}).catch(err => console.log(err))
console.log(5)
}
asyncFun1()
//打印出:1
// 第一个await命令后面的promise没有状态变化,后续任务不在执行
//await命令后面promise 状态发生了变化
const asyncFun1 = async function () {
console.log(1)
const res1 = await new Promise((resolve, reject) => {
resolve(2)
})
console.log(res1)
console.log(3)
await new Promise((resolve, reject) => {
reject(4)
}).catch()
console.log(5)
}
asyncFun1()
//输出:1 2 3
//第二个await命令后面但promise实例的 catch函数必须是执行了回调状态才会变为 fulfilled,
所以没再执行后面的任务
const asyncFun1 = async function () {
console.log(1)
await new Promise((resolve, reject) => {
resolve(2)
}).then(res => console.log(res))
console.log(3)
await new Promise((resolve, reject) => {
reject(4)
}).catch(err => console.log(err))
console.log(5)
}
asyncFun1()
//输出: 1 2 3 4 5
//两个promise 状态都变化为fulfilled 任务全部执行
//抛出异常
const asyncFun1 = async function () {
console.log(1)
await new Promise((resolve, reject) => {
throw new Error('error')
})
console.log(3)
}
asyncFun1().then(null, (err) => {
console.log(err)
})
//await后面promise抛出了异常会被当作变为了rejected状态,后面的任务不再执行
//输出: 1 Error: error
//有延时的宏任务执行
const asyncFun1 = async function () {
console.log(1)
await new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2)
}, 2000)
}).then(res => console.log(res))
console.log(3)
await new Promise((resolve, reject) => {
reject(4)
}).catch(err => console.log(err))
console.log(5)
}
asyncFun1()
//第一个promise里有延迟任务,等待延迟任务执行完后 再陆续执行后面的任务
//输出:1 2秒后 输出 2 3 4 5
错误处理
有时候希望即使前面的任务执行出错,后面的任务也还能继续执行,用 try catch 包裹会出错的任务
async function f7() {
try {
await Promise.reject('error')
await new Promise((resolve, reject) => {
throw new Error('error')
})
} catch (e) {
}
return await Promise.resolve('继续执行')
}
f7().then(res => console.log(res))
//输出:继续执行
案例:使用 try catch 实现 尝试重复多次
const test = (i) => {
let num = Math.floor(Math.random() * 10)
return new Promise((resolve, reject) => {
if (num % 2) {
console.log('resolve--', i)
resolve('fulfilled')
} else {
console.log('reject--', i)
reject('rejected')
}
})
}
async function f8() {
let i;
for (i = 0; i < 5; i++) {
try {
await test(i)
break
} catch (e) {
console.log(e, '----')
}
}
console.log(i)
}
f8()
/*reject-- 0
reject-- 1
reject-- 2
resolve-- 3
3*/
//await后面的如果成功,会执行break中断循环,如果失败被catch语句捕捉,继续循环
继发与并发
如果两个异步的操作互相不依赖不是继发关系,可以处理为并发执行
async function f9() {
// 写法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
// 写法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;
}
自己能力不足,还是把阮一峰老师的例子记录上,觉得以后会有这种场景出现需要使用到,
遇到不会的就先跟着手写一遍锻炼自己的手感,写着写着可能发现自己还是不会,不会就是不会。
DOM元素上部署多个动画操作,前一个结束后再执行下一个动画,如果有一个动画出错了,返回上一个动画。
//Promise写法
function f10(elem, animations) {
//用变量保存上一个动画返回值
let ret = null;
//建一个空的promise
let p = Promise.resolve()
//循环 then方法调用动画
for (let anim of animations) {
p = p.then((val) => {
ret = val;
return anim(elem)
})
}
//如果前一个动画报错p会走到catch方法,后面再接then方法返回上一个动画
return p.catch(err => {
console.log(err)
// 抛出错误,继续执行
}).then(() => {
return ret;
})
}
//async await写法
async function f11(elem, animations) {
let ret;
try {
for (let anim of animations) {
ret = await anim(elem)
}
} catch (e) {
//抛出错误,继续执行
}
return ret;
}
案例:
一组异步操作需要按照顺序完成,比如依次读取异步任务,不管其中哪个先执行结束,最后
还是要按照读取的顺序输出结果
//promise写法
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p1')
}, 3000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p2')
}, 1000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p3')
}, 2000)
})
let promises = [p1, p2, p3]
function f12(asyncTaskList) {
//先并发处理所有异步任务
const taskPromises = asyncTaskList.map((asyncTask) => {
return asyncTask.then(res => res)
})
console.log(taskPromises, '--taskPromises') //异步任务执行后的有返回值的 promise
//按次序输出
taskPromises.reduce((chain, taskPromise) => {
return chain.then(() => taskPromise).then(res => {
console.log(res)
})
}, Promise.resolve())
}
f12(promises)
//async函数实现
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p1')
}, 3000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p2')
}, 1000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p3')
}, 2000)
})
let promises = [p1, p2, p3]
async function f13(asyncTaskList) {
//并发处理任务
const taskPromises = asyncTaskList.map(async asyncTask => {
return await asyncTask
})
//按次序输出
for (let task of taskPromises) {
console.log(await task)
}
}
f13(promises)
//过程的推理演算
async function f14() {
const res = await new Promise((resolve, reject)=>{resolve(123)})
return res
}
// f14().then(res=>console.log(res))
//123
async function f15() {
console.log(await f14())
//f14()是状态为fulfilled且有返回值的promise实例
//此时在f15() 前面又使用await命令
//等同于
/* const res = await f14()
console.log(res)*/
}
f15()
//123