Async函数详解
核心特性
Async函数本质上是对生成器函数的改进和简化。通过对比两种实现方式可以看出其本质:
const { promisify } = require("util");
const path = require('path');
const readFile = promisify(require('fs').readFile);
const fileA = path.join(__dirname, './data/a.txt');
const fileB = path.join(__dirname, './data/b.txt');
// 使用生成器函数实现
function* generatorApproach() {
const result1 = yield readFile(fileA);
console.log('文件A读取完成: ' + result1);
const result2 = yield readFile(fileB);
console.log('文件B读取完成: ' + result2);
}
// 使用async函数实现
async function asyncApproach() {
const result1 = await readFile(fileA);
console.log('文件A读取完成: ' + result1);
const result2 = await readFile(fileB);
console.log('文件B读取完成: ' + result2);
}
可以看出,async函数将生成器的*符号替换为async,yield替换为await。
函数声明与调用
通过async关键字声明函数:
async function processData() {
const content1 = await readFile(fileA);
console.log('处理步骤1: ' + content1);
const content2 = await readFile(fileB);
console.log('处理步骤2: ' + content2);
}
调用async函数会返回Promise对象,即使函数内部没有显式返回Promise:
async function simpleTask() {
console.log('执行任务');
}
simpleTask().then(() => {
console.log('任务完成');
});
async function taskWithResult() {
console.log('执行任务');
return 'success';
}
taskWithResult().then(result => {
console.log('结果: ' + result);
});
Await操作符行为
与yield类似,await用于暂停函数执行并等待Promise解决:
- 当await后面是Promise时,函数会等待Promise解决后继续执行,并将解决值作为await表达式的结果
- 当await后面是非Promise值时,会立即继续执行后续代码,await表达式结果为该值本身
async function handlePromise() {
const value = await new Promise(resolve => {
setTimeout(() => resolve('延迟数据'), 1000);
});
console.log(value);
}
async function handleValue() {
const value = await '直接数据';
console.log(value);
}
异常处理机制
当await的Promise被拒绝或出现异常时,后续代码不会执行,需要使用try-catch捕获:
async function errorHandling() {
try {
const data = await new Promise((_, reject) => {
setTimeout(() => reject('操作失败'), 1000);
});
console.log('这行不会执行');
} catch (error) {
console.log('捕获错误: ' + error);
}
}
并发异步操作
默认情况下,async函数中的await操作是串行执行的。如需并发执行,可结合Promise.all:
async function concurrentTasks() {
const startTime = Date.now();
const [result1, result2] = await Promise.all([
new Promise(resolve => {
setTimeout(() => resolve('任务1'), 2000);
}),
new Promise(resolve => {
setTimeout(() => resolve('任务2'), 3000);
})
]);
console.log(`${result1}, ${result2}, 总耗时: ${Date.now() - startTime}ms`);
}
与传统Promise的对比
使用async函数编写异步逻辑比传统Promise链更清晰直观:
const { readFile } = require('fs');
const { promisify } = require('util');
const readFileAsync = promisify(readFile);
const file1 = path.join(__dirname, './files/first.txt');
const file2 = path.join(__dirname, './files/second.txt');
const file3 = path.join(__dirname, './files/third.txt');
// Promise链式调用
function promiseChain() {
readFileAsync(file1).then(data1 => {
console.log('第一步: ' + data1);
return readFileAsync(file2);
}).then(data2 => {
console.log('第二步: ' + data2);
return readFileAsync(file3);
}).then(data3 => {
console.log('第三步: ' + data3);
});
}
// Async函数实现
async function asyncImplementation() {
const data1 = await readFileAsync(file1);
console.log('第一步: ' + data1);
const data2 = await readFileAsync(file2);
console.log('第二步: ' + data2);
const data3 = await readFileAsync(file3);
console.log('第三步: ' + data3);
}