还是大剑师兰特:曾是美国某知名大学计算机专业研究生,现为航空航海领域高级前端工程师;CSDN知名博主,GIS领域优质创作者,深耕openlayers、leaflet、mapbox、cesium,canvas,webgl,echarts等技术开发,欢迎加底部微信(gis-dajianshi),一起交流。
No. | 内容链接 |
---|---|
1 | Openlayers 【入门教程】 - 【源代码+示例300+】 |
2 | Leaflet 【入门教程】 - 【源代码+图文示例 150+】 |
3 | Cesium 【入门教程】 - 【源代码+图文示例200+】 |
4 | MapboxGL【入门教程】 - 【源代码+图文示例150+】 |
5 | 前端就业宝典 【面试题+详细答案 1000+】 |
async/await
是 JavaScript 异步编程的一种简化写法,它建立在 Promise 基础之上,提供了更加简洁和易于理解的方式来处理异步操作。以下是 async/await
的关键字、应用场景、示例代码以及注意事项。
一、关键字
-
async 关键字:
async
关键字用于声明一个函数为异步函数。- 异步函数总是返回一个 Promise,即使没有明确地返回一个 Promise,也会隐式地将其返回值包装在一个 resolved Promise 中。
- 如果异步函数返回了一个非 Promise 值,它会被转换为 resolved Promise,返回值作为 resolve 的参数。
-
await 关键字:
await
关键字只能在async
函数内部使用。await
后跟一个表达式,这个表达式的值通常是一个 Promise。- 当遇到
await
表达式时,JavaScript 会暂停异步函数的执行,等待 Promise 解决(resolved)或拒绝(rejected),然后恢复执行并返回 Promise 的结果或抛出错误。
二、应用场景
- 当需要串行处理多个异步操作时,
async/await
可以帮助消除回调地狱(callback hell)和链式.then()
方法带来的嵌套层次过深的问题。 - 在 Node.js 中,用于处理文件 I/O、数据库查询、网络请求等异步操作,使得代码逻辑更加清晰、易于维护。
三、示例代码
// 异步获取数据的模拟函数
function getDataFromApi(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.5) {
resolve(`Data from ${url}`);
} else {
reject(new Error('Failed to fetch data'));
}
}, 1000); // 模拟异步延迟
});
}
// 使用 async/await 的异步函数
async function fetchDataSequentially(urls) {
let results = [];
for (const url of urls) {
try {
const data = await getDataFromApi(url);
results.push(data);
} catch (error) {
console.error(`Error fetching data from ${url}:`, error);
}
}
return results;
}
// 使用示例
(async () => {
const urls = ['api1', 'api2', 'api3'];
try {
const fetchedData = await fetchDataSequentially(urls);
console.log(fetchedData);
} catch (error) {
console.error('An error occurred:', error);
}
})();
在上面的示例中,fetchDataSequentially
是一个异步函数,它逐个等待 getDataFromApi
的 Promise 完成,并将结果收集到数组 results
中。整个过程无需回调函数或 .then()
链式调用,代码如同同步执行般直观。注意,为了能够启动这个异步操作,我们在全局作用域使用了立即执行的 async 函数表达式 ((async () => {...})()
)。
四、注意事项:
使用 async/await
时,需要注意以下几点:
-
函数必须带有
async
关键字:- 若要在函数内部使用
await
关键字,该函数必须被声明为async
函数。否则会引发语法错误。
- 若要在函数内部使用
-
await
后接 Promise:await
关键字后面通常跟着一个返回 Promise 的表达式。如果不是 Promise,它会被转换为已解决(resolved)的 Promise。- 如果
await
后的 Promise 被拒绝(rejected),那么await
表达式将会抛出错误,需要用try...catch
语句捕获。
-
同步外观下的异步行为:
- 尽管
async/await
提供了类似于同步代码的写法,但实际上它仍然执行的是异步操作。这意味着await
之后的代码并不会阻塞执行流,而是等待 Promise 解决后才会继续执行。 - 因此,在某些情况下,需要特别注意代码执行的顺序,特别是涉及多个异步操作时,避免误认为所有操作会按顺序立即执行。
- 尽管
-
错误处理:
- 使用
async/await
编写异步代码时,应该适当地使用try...catch
结构来捕获和处理可能出现的错误。如果不这样做,Promise 的 rejection 将会导致异常冒泡至外层的async
函数,并且如果没有被捕获,会导致整个脚本终止。
- 使用
-
并发 vs. 串行:
- 在循环中使用
await
时,代码默认会按照顺序逐个等待异步操作完成,即串行执行。如果需要并发执行多个异步任务,可以利用Promise.all
或者for...of
结合await
实现。
- 在循环中使用
-
资源管理:
- 在执行一系列异步操作时,尤其涉及数据库连接、文件流或者其他需要释放的资源,要注意及时关闭或释放资源,确保资源在使用完毕后得到妥善处理。
-
避免阻塞:
- 尽管
async/await
使得代码看上去像是同步的,但应当避免在长时间运行的操作前后不加区分地使用await
,以免阻塞事件循环,影响应用的响应性。
- 尽管
-
内存占用和性能考量:
- 如果大量的异步操作堆积在一起,可能会增加内存消耗,因为每一个
async
函数都会生成一个微型任务,加入到任务队列中。在高负载的情况下,需要合理设计异步流程以降低内存压力。
- 如果大量的异步操作堆积在一起,可能会增加内存消耗,因为每一个
-
跨函数传播:
- 由于
async
函数始终返回一个 Promise,因此在跨函数调用时,需确保下游函数也能正确处理 Promise,或者也将下游函数声明为async
函数以便使用await
。
- 由于
-
兼容性和迁移成本:
- 虽然现代浏览器和 Node.js 已经全面支持
async/await
,但在旧版本环境中可能需要 Babel 等转译工具来确保兼容性。在已有项目中引入async/await
可能涉及到大量既有代码的重构。
- 虽然现代浏览器和 Node.js 已经全面支持