本文深入解析 JavaScript ES2017 引入的 async 与 await 特性,阐述其如何简化基于 Promise 的异步编程。详细说明了 async 函数返回 Promise 对象的机制,await 关键字对后续代码执行的阻塞行为,以及两者结合时的执行顺序。同时提供了 try...catch 和 .catch 两种异常处理方案,帮助开发者更清晰地掌握异步代码的编写与调试。
1、前言
async 函数,即常说的 async/await,是 ES2017 (ES8) 引入的新特性,旨在简化基于 Promise API 的语法使用。async 和 await 关键字允许开发者以更简洁的方式编写基于 Promise 的异步逻辑,无需进行繁琐的链式调用。
2、详解
async 用于标识函数中包含异步操作,而 await 则指示其后的表达式必须等待结果。需注意,await 关键字仅在 async 函数内部有效,若在 async 函数体外使用,将引发语法错误。
2.1、async
async 函数始终返回一个 Promise 对象,可通过 then 方法添加回调。无论函数内部是否返回 Promise 对象,只要使用了 async,返回值都会被自动包装为 Promise 对象。
具体效果见以下代码示例:
2.1.1、函数返回非Promise对象
async function testAsync() {
return "hello async";
}
const result = testAsync();
console.log(result);

当函数直接返回字符串时,结果仍为 Promise 对象,相当于通过 Promise.resolve() 将字符串封装。若函数无返回值,PromiseResult 结果为 undefined。
2.1.2、函数返回Promise对象
async function testAsync() {
return new Promise(function(resolve, reject) {
if (true) {
resolve('resolve return')
} else {
reject('reject return')
}
})
}
console.log(testAsync());

此时返回值同样为 Promise 对象。
2.2、await
await 关键字可置于任意变量或表达式之前,通常后跟异步过程。使用 await 时,会阻塞后续代码的执行。此处暂不讨论 async,单独分析 await。
由于 await 只能在标记为 async 的函数内使用,请在浏览器控制台执行以下示例以观察效果。
function testAsync() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
if (true) {
console.log('请求中...')
resolve('resolve return')
} else {
reject('reject return')
}
}, 2000)
})
}
var result = await testAsync();
var result1 = await "testAsync后执行";
console.log(result);
console.log(result1);

可见,使用 await 后,必须等待 testAsync 方法执行完毕,才会继续执行后续代码。尝试移除 testAsync 前的 async 关键字,对比加上 await 时的区别。
2.3、async、await结合使用
针对 await 阻塞后续代码的问题,需结合 async 使用。使用 async 后,函数执行至 await 时会先返回 Promise 对象,待 await 后的操作完成,再继续执行 async 函数体内的剩余语句。
语法如下:
async function 函数名() {
await XXX;
}
示例代码如下:
function testAsync() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
if (true) {
console.log('请求中...')
resolve('resolve return')
} else {
reject('reject return')
}
}, 2000)
})
}
function testAsync2() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
if (true) {
console.log('请求中2...')
resolve('resolve return2')
} else {
reject('reject return2')
}
}, 2000)
})
}
async function test() {
console.log('test开始...');
var value1 = await testAsync();
console.log(value1);
var value2 = await testAsync2();
console.log(value2);
var value3 = await 'test结束...';
console.log(value3);
}
console.log(test());

由上图可知,遇到第一个 await 后,立即返回 Promise 对象,随后按顺序执行 testAsync 函数,待其执行完毕后再执行 testAsync2 函数。此外,async 函数可简化 Promise 语法,以往需使用 .then 处理回调,现在可像编写同步代码一样使用 await 处理异步逻辑。
在此基础上,加入两个普通函数进行升级:
function fun1() {
return '函数1'
}
function fun2() {
return '函数2'
}
function fun3() {
console.log(fun1());
console.log(test()); // async/await函数
console.log(fun2());
}
console.log(fun3());

首先梳理函数的执行过程:
1、先执行函数1
2、进入 test 函数并输出开始
3、在 test 函数中遇到 await,立即返回 Promise 对象
4、执行函数2
5、执行 test 函数中的 testAsync 方法
6、等到 test 函数中的 testAsync 方法执行完后,继续执行 testAsync2 方法
7、test 函数结束
可见,async 函数在遇到 await 后会立即返回 Promise 对象,继续执行 async 函数外部的后续逻辑,而 async 函数内部会被 await 阻塞并按顺序执行代码逻辑。
2.4、async、await异常处理
await 后的函数可能出现异常,建议将 await 命令置于 try...catch 代码块中。若 await 后是 Promise 对象,也可使用 .catch 进行捕获。
// 第一种写法
async function myFunction() {
try {
await something();
} catch (err) {
console.log(err);
}
}
// 第二种写法
async function myFunction() {
await somethingPromise()
.catch(function (err) {
console.log(err);
});
}
3、总结
async 函数在遇到 await 后会立即返回 Promise 对象,继续执行 async 函数外部逻辑,async 函数内部会被 await 阻塞并按顺序执行代码逻辑。
可使用 try...catch 或 .catch 对 async 函数进行异常处理。
到此这篇关于 JavaScript 中 async 与 await 的文章就介绍到这了,更多相关 JavaScript async await 内容请搜索本站以前的文章或继续浏览下面的相关文章,希望大家以后多多支持本站!