公司的前端工程使用了ES6语法,最近看代码的时候还是有很多疑惑的,记录一下async/await相关知识
1. async function
使用谷歌浏览器开发者工具写脚本进行测试
- 按F12打开开发者工具
- 点击
Source
- 在左侧选择
Snippets
,点击New snippets创建一个新文件
- 输入以下代码
async function add(x) {
let a = 1;
return x + a;
}
add(10);
- 运行此脚本,在控制台可以看到有结果输出
- 返回的结果是一个Promise对象,状态是
fulfilled
,值是11
2. await语法
- await 放置在Promise调用之前,强制后面的代码等待,直到Promise对象resolve,得到resolve的值作为await表达式的运算结果
- await只能在async函数内部使用,用在普通函数里会报错
新建一个脚本文件,输入以下代码:
function test_promise() {
return new Promise(function(resolve, reject) {
resolve('resolve result')
});
}
async function run_test() {
let a = await test_promise()
let b = await ' and a simple string'
console.log(a)
console.log(b)
return a + b
}
run_test();
运行结果为:
给test_promise方法添加延时,修改test_promise()方法
function test_promise() {
return new Promise(function(resolve, reject) {
setTimeout(() => {
resolve('resolve result')
}, 3000)
});
}
运行结果为:
注意,PromiseResult的值即为run_test()
方法的返回值
3. 错误处理
3.1
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(() => {reject('error')}, ms);
});
}
async function asyncPrint(ms) {
console.log('start');
await timeout(ms); //这里返回了错误
console.log('end'); //所以这句代码不会被执行了
}
asyncPrint(1000);
运行结果:
本例中我们并没有捕获错误,控制台打印 Uncaught error
3.2 捕获错误
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(() => {reject('error')}, ms); //reject模拟出错,返回error
});
}
// 使用 try catch 捕获异常,包括promise对象reject的数据或者抛出的异常
async function asyncPrint(ms) {
try {
console.log('start');
await timeout(ms);
console.log('end');
} catch(err) {
console.log(err);
}
}
asyncPrint(1000);
或者使用如下方式捕获异常
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(() => {reject('error')}, ms); //reject模拟出错,返回error
});
}
async function asyncPrint(ms) {
console.log('start');
await timeout(ms)
console.log('end');
}
asyncPrint(1000).catch(err => {
console.log(err)
});
运行结果:
首先打印了start,然后在执行timeout
函数时,调用reject
回调。错误被捕获,打印出"error"。
如果想在出现异常后仍然执行后续代码,示例代码如下:
function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('error')
}, ms);
});
}
async function asyncPrint(ms) {
console.log('start');
await timeout(ms).catch(err => {
console.log(err)
})
console.log('end');
}
asyncPrint(1000);
运行结果:
4. Promise.all()
多个await命令的异步操作,如果不存在依赖关系(后面的await不依赖前一个await返回的结果),用Promise.all()让它们同时触发
function test1 () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000)
})
}
function test2 () {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(2)
}, 2000)
})
}
async function exc1 () {
console.log('exc1 start:',Date.now())
let res1 = await test1();
let res2 = await test2();
console.log('exc1 end:', Date.now())
}
async function exc2 () {
console.log('exc2 start:',Date.now())
let [res1, res2] = await Promise.all([test1(), test2()])
console.log('exc2 end:', Date.now())
}
exc1();
exc2();
运行上述代码可得,执行exc1函数耗时约为3秒,而执行exc2函数耗时约为2秒。表明在exc2函数中, 使用Promise.all同时触发了test1和test2这2个异步函数。