Search K
Appearance
Appearance
📊 SEO元描述:2024年最新Node.js异步编程教程,详解回调函数、Promise链式调用、async/await语法糖、错误处理最佳实践。包含完整代码示例,适合Node.js开发者掌握异步编程核心技能。
核心关键词:Node.js异步编程、回调函数、Promise、async await、异步错误处理、JavaScript异步、事件驱动编程
长尾关键词:Node.js怎么处理异步、回调地狱解决方案、Promise链式调用技巧、async await最佳实践、异步编程错误处理
通过本节Node.js异步编程基础的学习,你将系统性掌握:
什么是回调函数?为什么Node.js大量使用回调?回调函数是Node.js异步编程的基础模式,通过将函数作为参数传递来处理异步操作的结果。虽然现在有了更现代的Promise和async/await,但理解回调函数对于掌握Node.js异步编程本质仍然至关重要。
💡 设计理念:Node.js的回调模式体现了"不要等待,继续工作"的哲学,这是其高性能的关键所在。
// 🎉 Node.js回调函数完整示例
const fs = require('fs');
const path = require('path');
// === 基础回调模式 ===
// 1. 简单的异步回调
function readFileCallback(filename, callback) {
console.log(`开始读取文件: ${filename}`);
fs.readFile(filename, 'utf8', (error, data) => {
if (error) {
console.error('文件读取失败:', error.message);
callback(error, null);
return;
}
console.log(`文件读取成功: ${filename}`);
callback(null, data);
});
console.log('文件读取请求已发出,继续执行其他代码...');
}
// 2. 错误优先回调模式(Error-First Callback)
function processUserData(userId, callback) {
// 模拟数据库查询
setTimeout(() => {
if (!userId || userId < 1) {
const error = new Error('无效的用户ID');
error.code = 'INVALID_USER_ID';
callback(error, null);
return;
}
if (userId === 999) {
const error = new Error('用户不存在');
error.code = 'USER_NOT_FOUND';
callback(error, null);
return;
}
// 成功情况
const userData = {
id: userId,
name: `用户${userId}`,
email: `user${userId}@example.com`,
createdAt: new Date().toISOString()
};
callback(null, userData);
}, Math.random() * 1000); // 模拟网络延迟
}
// 3. 回调地狱问题演示
function demonstrateCallbackHell() {
console.log('\n=== 回调地狱演示 ===');
// 嵌套回调导致的"回调地狱"
fs.readFile('config.json', 'utf8', (err1, configData) => {
if (err1) {
console.error('读取配置失败:', err1.message);
return;
}
const config = JSON.parse(configData);
fs.readFile(config.userDataFile, 'utf8', (err2, userData) => {
if (err2) {
console.error('读取用户数据失败:', err2.message);
return;
}
const users = JSON.parse(userData);
fs.readFile(config.logFile, 'utf8', (err3, logData) => {
if (err3) {
console.error('读取日志失败:', err3.message);
return;
}
// 处理所有数据
console.log('所有文件读取完成,开始处理数据...');
processAllData(config, users, logData, (err4, result) => {
if (err4) {
console.error('数据处理失败:', err4.message);
return;
}
console.log('数据处理完成:', result);
});
});
});
});
}
// 4. 回调地狱的解决方案:函数分离
function readConfig(callback) {
fs.readFile('config.json', 'utf8', (error, data) => {
if (error) {
callback(error, null);
return;
}
try {
const config = JSON.parse(data);
callback(null, config);
} catch (parseError) {
callback(parseError, null);
}
});
}
function readUserData(filename, callback) {
fs.readFile(filename, 'utf8', (error, data) => {
if (error) {
callback(error, null);
return;
}
try {
const users = JSON.parse(data);
callback(null, users);
} catch (parseError) {
callback(parseError, null);
}
});
}
function readLogData(filename, callback) {
fs.readFile(filename, 'utf8', callback);
}
function processAllData(config, users, logs, callback) {
// 模拟数据处理
setTimeout(() => {
const result = {
configLoaded: !!config,
userCount: users ? users.length : 0,
logSize: logs ? logs.length : 0,
processedAt: new Date().toISOString()
};
callback(null, result);
}, 100);
}
// 改进后的流程控制
function improvedAsyncFlow() {
console.log('\n=== 改进的异步流程 ===');
readConfig((err1, config) => {
if (err1) {
console.error('配置读取失败:', err1.message);
return;
}
readUserData(config.userDataFile, (err2, users) => {
if (err2) {
console.error('用户数据读取失败:', err2.message);
return;
}
readLogData(config.logFile, (err3, logs) => {
if (err3) {
console.error('日志读取失败:', err3.message);
return;
}
processAllData(config, users, logs, (err4, result) => {
if (err4) {
console.error('数据处理失败:', err4.message);
return;
}
console.log('改进流程处理完成:', result);
});
});
});
});
}
// === 并行回调处理 ===
class ParallelCallbackManager {
static executeParallel(tasks, callback) {
const results = [];
const errors = [];
let completedCount = 0;
if (tasks.length === 0) {
callback(null, []);
return;
}
tasks.forEach((task, index) => {
task((error, result) => {
if (error) {
errors[index] = error;
} else {
results[index] = result;
}
completedCount++;
if (completedCount === tasks.length) {
// 所有任务完成
if (errors.some(err => err)) {
callback(errors, results);
} else {
callback(null, results);
}
}
});
});
}
// 使用示例
static demonstrateParallel() {
console.log('\n=== 并行回调处理演示 ===');
const tasks = [
(cb) => processUserData(1, cb),
(cb) => processUserData(2, cb),
(cb) => processUserData(3, cb)
];
this.executeParallel(tasks, (errors, results) => {
if (errors && errors.some(err => err)) {
console.error('部分任务失败:', errors);
}
console.log('并行任务结果:', results);
});
}
}
// 运行演示
readFileCallback('package.json', (error, data) => {
if (error) {
console.error('回调示例失败:', error.message);
} else {
console.log('回调示例成功,文件大小:', data.length);
}
});
processUserData(123, (error, userData) => {
if (error) {
console.error('用户数据处理失败:', error.message);
} else {
console.log('用户数据:', userData);
}
});
ParallelCallbackManager.demonstrateParallel();Promise是解决回调地狱的现代方案,提供了更清晰的异步编程模式。
// 🎉 Promise链式调用完整示例
const fs = require('fs').promises;
const path = require('path');
// === Promise基础 ===
// 1. 创建Promise
function createPromiseExample() {
return new Promise((resolve, reject) => {
const randomSuccess = Math.random() > 0.3;
setTimeout(() => {
if (randomSuccess) {
resolve({
message: 'Promise执行成功',
timestamp: new Date().toISOString(),
data: { value: Math.random() }
});
} else {
reject(new Error('Promise执行失败'));
}
}, 1000);
});
}
// 2. Promise化回调函数
function promisifyCallback(fn) {
return function(...args) {
return new Promise((resolve, reject) => {
fn(...args, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
};
}
// 将回调函数转换为Promise
const readFilePromise = promisifyCallback(require('fs').readFile);
// 3. Promise链式调用
class PromiseChainDemo {
static async demonstrateChaining() {
console.log('\n=== Promise链式调用演示 ===');
try {
const result = await fs.readFile('package.json', 'utf8')
.then(data => {
console.log('✅ 文件读取成功');
return JSON.parse(data);
})
.then(packageInfo => {
console.log('✅ JSON解析成功');
return {
name: packageInfo.name,
version: packageInfo.version,
dependencies: Object.keys(packageInfo.dependencies || {})
};
})
.then(processedData => {
console.log('✅ 数据处理成功');
return {
...processedData,
processedAt: new Date().toISOString(),
dependencyCount: processedData.dependencies.length
};
})
.catch(error => {
console.error('❌ Promise链中发生错误:', error.message);
throw error;
});
console.log('Promise链最终结果:', result);
return result;
} catch (error) {
console.error('Promise链执行失败:', error.message);
}
}
// 4. 复杂的Promise链
static complexPromiseChain() {
console.log('\n=== 复杂Promise链演示 ===');
return this.loadConfiguration()
.then(config => this.validateConfiguration(config))
.then(validConfig => this.loadUserData(validConfig))
.then(({ config, users }) => this.processUsers(config, users))
.then(processedData => this.saveResults(processedData))
.then(saveResult => {
console.log('✅ 复杂流程执行完成:', saveResult);
return saveResult;
})
.catch(error => {
console.error('❌ 复杂流程执行失败:', error.message);
throw error;
});
}
static loadConfiguration() {
console.log('📁 加载配置文件...');
return new Promise((resolve) => {
setTimeout(() => {
resolve({
database: { host: 'localhost', port: 5432 },
api: { timeout: 5000, retries: 3 },
features: { logging: true, caching: true }
});
}, 100);
});
}
static validateConfiguration(config) {
console.log('✅ 验证配置...');
return new Promise((resolve, reject) => {
setTimeout(() => {
if (!config.database || !config.api) {
reject(new Error('配置验证失败:缺少必要配置'));
return;
}
resolve(config);
}, 50);
});
}
static loadUserData(config) {
console.log('👥 加载用户数据...');
return new Promise((resolve) => {
setTimeout(() => {
const users = [
{ id: 1, name: '张三', active: true },
{ id: 2, name: '李四', active: false },
{ id: 3, name: '王五', active: true }
];
resolve({ config, users });
}, 200);
});
}
static processUsers(config, users) {
console.log('⚙️ 处理用户数据...');
return new Promise((resolve) => {
setTimeout(() => {
const activeUsers = users.filter(user => user.active);
const processedData = {
config,
totalUsers: users.length,
activeUsers: activeUsers.length,
userList: activeUsers,
processedAt: new Date().toISOString()
};
resolve(processedData);
}, 150);
});
}
static saveResults(data) {
console.log('💾 保存处理结果...');
return new Promise((resolve) => {
setTimeout(() => {
resolve({
saved: true,
filename: `results_${Date.now()}.json`,
size: JSON.stringify(data).length
});
}, 100);
});
}
}
// === Promise并行处理 ===
class PromiseParallelDemo {
static async demonstrateParallel() {
console.log('\n=== Promise并行处理演示 ===');
// Promise.all - 所有Promise都成功才成功
try {
console.log('🚀 开始并行执行...');
const startTime = Date.now();
const results = await Promise.all([
this.fetchUserData(1),
this.fetchUserData(2),
this.fetchUserData(3),
this.fetchSystemInfo()
]);
const endTime = Date.now();
console.log(`✅ Promise.all完成,耗时: ${endTime - startTime}ms`);
console.log('并行结果:', results);
} catch (error) {
console.error('❌ Promise.all失败:', error.message);
}
// Promise.allSettled - 等待所有Promise完成(无论成功失败)
try {
console.log('\n🔄 使用Promise.allSettled...');
const settledResults = await Promise.allSettled([
this.fetchUserData(1),
this.fetchUserData(999), // 这个会失败
this.fetchUserData(3),
this.fetchSystemInfo()
]);
console.log('Promise.allSettled结果:');
settledResults.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(` 任务${index + 1}: ✅ 成功`, result.value);
} else {
console.log(` 任务${index + 1}: ❌ 失败`, result.reason.message);
}
});
} catch (error) {
console.error('Promise.allSettled错误:', error.message);
}
// Promise.race - 第一个完成的Promise决定结果
try {
console.log('\n🏃 使用Promise.race...');
const raceResult = await Promise.race([
this.slowOperation('操作A', 2000),
this.slowOperation('操作B', 1000),
this.slowOperation('操作C', 1500)
]);
console.log('Promise.race获胜者:', raceResult);
} catch (error) {
console.error('Promise.race失败:', error.message);
}
}
static fetchUserData(userId) {
return new Promise((resolve, reject) => {
const delay = Math.random() * 500 + 100;
setTimeout(() => {
if (userId === 999) {
reject(new Error(`用户${userId}不存在`));
return;
}
resolve({
id: userId,
name: `用户${userId}`,
fetchTime: delay.toFixed(0) + 'ms'
});
}, delay);
});
}
static fetchSystemInfo() {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
system: 'Node.js',
version: process.version,
uptime: process.uptime(),
memory: Math.round(process.memoryUsage().heapUsed / 1024 / 1024) + 'MB'
});
}, 300);
});
}
static slowOperation(name, delay) {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
operation: name,
completedAt: new Date().toISOString(),
delay
});
}, delay);
});
}
}
// 运行Promise演示
createPromiseExample()
.then(result => {
console.log('Promise示例成功:', result);
})
.catch(error => {
console.error('Promise示例失败:', error.message);
});
PromiseChainDemo.demonstrateChaining();
PromiseChainDemo.complexPromiseChain();
PromiseParallelDemo.demonstrateParallel();async/await是Promise的语法糖,让异步代码看起来像同步代码,是现代JavaScript异步编程的首选方式。
// 🎉 async/await完整示例
const fs = require('fs').promises;
const path = require('path');
// === async/await基础 ===
// 1. 基本async/await语法
async function basicAsyncAwait() {
console.log('\n=== async/await基础演示 ===');
try {
console.log('开始异步操作...');
// await会等待Promise完成
const data = await fs.readFile('package.json', 'utf8');
console.log('✅ 文件读取完成');
const packageInfo = JSON.parse(data);
console.log('✅ JSON解析完成');
const result = {
name: packageInfo.name,
version: packageInfo.version,
hasScripts: !!packageInfo.scripts
};
console.log('async/await结果:', result);
return result;
} catch (error) {
console.error('❌ async/await操作失败:', error.message);
throw error;
}
}
// 2. 复杂的async/await流程
class AsyncAwaitDemo {
static async complexAsyncFlow() {
console.log('\n=== 复杂async/await流程 ===');
try {
// 串行执行
const config = await this.loadConfig();
const users = await this.loadUsers(config);
const processedData = await this.processData(users);
const result = await this.saveData(processedData);
console.log('✅ 复杂流程完成:', result);
return result;
} catch (error) {
console.error('❌ 复杂流程失败:', error.message);
throw error;
}
}
static async loadConfig() {
console.log('📁 加载配置...');
// 模拟异步操作
await new Promise(resolve => setTimeout(resolve, 100));
return {
database: 'mongodb://localhost:27017',
cacheSize: 1000,
timeout: 5000
};
}
static async loadUsers(config) {
console.log('👥 加载用户数据...');
await new Promise(resolve => setTimeout(resolve, 200));
return [
{ id: 1, name: '张三', email: 'zhang@example.com' },
{ id: 2, name: '李四', email: 'li@example.com' },
{ id: 3, name: '王五', email: 'wang@example.com' }
];
}
static async processData(users) {
console.log('⚙️ 处理数据...');
await new Promise(resolve => setTimeout(resolve, 150));
return {
totalUsers: users.length,
userEmails: users.map(user => user.email),
processedAt: new Date().toISOString()
};
}
static async saveData(data) {
console.log('💾 保存数据...');
await new Promise(resolve => setTimeout(resolve, 100));
return {
saved: true,
filename: `data_${Date.now()}.json`,
size: JSON.stringify(data).length
};
}
// 3. 并行async/await
static async parallelAsyncAwait() {
console.log('\n=== 并行async/await演示 ===');
try {
const startTime = Date.now();
// 并行执行多个异步操作
const [userData, systemInfo, configData] = await Promise.all([
this.fetchUserProfile(123),
this.getSystemStatus(),
this.loadApplicationConfig()
]);
const endTime = Date.now();
console.log(`✅ 并行操作完成,耗时: ${endTime - startTime}ms`);
return {
user: userData,
system: systemInfo,
config: configData,
executionTime: endTime - startTime
};
} catch (error) {
console.error('❌ 并行操作失败:', error.message);
throw error;
}
}
static async fetchUserProfile(userId) {
await new Promise(resolve => setTimeout(resolve, 300));
return {
id: userId,
name: `用户${userId}`,
profile: { avatar: 'avatar.jpg', bio: '这是用户简介' }
};
}
static async getSystemStatus() {
await new Promise(resolve => setTimeout(resolve, 200));
return {
status: 'healthy',
uptime: process.uptime(),
memory: process.memoryUsage()
};
}
static async loadApplicationConfig() {
await new Promise(resolve => setTimeout(resolve, 100));
return {
version: '1.0.0',
environment: 'development',
features: ['logging', 'caching', 'monitoring']
};
}
// 4. 错误处理和重试机制
static async withRetry(operation, maxRetries = 3, delay = 1000) {
let lastError;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
console.log(`尝试第${attempt}次执行操作...`);
const result = await operation();
console.log(`✅ 第${attempt}次尝试成功`);
return result;
} catch (error) {
lastError = error;
console.error(`❌ 第${attempt}次尝试失败:`, error.message);
if (attempt < maxRetries) {
console.log(`等待${delay}ms后重试...`);
await new Promise(resolve => setTimeout(resolve, delay));
delay *= 2; // 指数退避
}
}
}
throw new Error(`操作失败,已重试${maxRetries}次。最后错误: ${lastError.message}`);
}
// 5. 条件异步执行
static async conditionalAsync(condition) {
console.log('\n=== 条件异步执行演示 ===');
try {
let result;
if (condition === 'user') {
result = await this.handleUserOperation();
} else if (condition === 'admin') {
result = await this.handleAdminOperation();
} else if (condition === 'system') {
result = await this.handleSystemOperation();
} else {
result = await this.handleDefaultOperation();
}
console.log('条件异步执行结果:', result);
return result;
} catch (error) {
console.error('条件异步执行失败:', error.message);
throw error;
}
}
static async handleUserOperation() {
await new Promise(resolve => setTimeout(resolve, 100));
return { type: 'user', action: 'profile_updated' };
}
static async handleAdminOperation() {
await new Promise(resolve => setTimeout(resolve, 200));
return { type: 'admin', action: 'system_configured' };
}
static async handleSystemOperation() {
await new Promise(resolve => setTimeout(resolve, 150));
return { type: 'system', action: 'maintenance_completed' };
}
static async handleDefaultOperation() {
await new Promise(resolve => setTimeout(resolve, 50));
return { type: 'default', action: 'basic_operation' };
}
}
// === 实际应用示例:文件处理器 ===
class AsyncFileProcessor {
constructor(basePath = './') {
this.basePath = basePath;
}
async processFiles(fileList) {
console.log('\n=== 异步文件处理器演示 ===');
const results = [];
for (const filename of fileList) {
try {
const result = await this.processFile(filename);
results.push(result);
console.log(`✅ 文件处理完成: ${filename}`);
} catch (error) {
console.error(`❌ 文件处理失败: ${filename}`, error.message);
results.push({ filename, error: error.message });
}
}
return results;
}
async processFile(filename) {
const filePath = path.join(this.basePath, filename);
// 检查文件是否存在
try {
await fs.access(filePath);
} catch (error) {
throw new Error(`文件不存在: ${filename}`);
}
// 读取文件
const content = await fs.readFile(filePath, 'utf8');
// 分析文件
const analysis = await this.analyzeContent(content);
// 生成报告
const report = await this.generateReport(filename, analysis);
return report;
}
async analyzeContent(content) {
// 模拟内容分析
await new Promise(resolve => setTimeout(resolve, 50));
return {
size: content.length,
lines: content.split('\n').length,
words: content.split(/\s+/).length,
characters: content.length
};
}
async generateReport(filename, analysis) {
// 模拟报告生成
await new Promise(resolve => setTimeout(resolve, 30));
return {
filename,
analysis,
generatedAt: new Date().toISOString(),
summary: `文件${filename}包含${analysis.lines}行,${analysis.words}个单词`
};
}
}
// 运行async/await演示
(async () => {
try {
await basicAsyncAwait();
await AsyncAwaitDemo.complexAsyncFlow();
await AsyncAwaitDemo.parallelAsyncAwait();
// 重试机制演示
const unreliableOperation = () => {
return new Promise((resolve, reject) => {
if (Math.random() > 0.7) {
resolve('操作成功');
} else {
reject(new Error('随机失败'));
}
});
};
const retryResult = await AsyncAwaitDemo.withRetry(unreliableOperation);
console.log('重试机制结果:', retryResult);
// 条件异步执行演示
await AsyncAwaitDemo.conditionalAsync('user');
await AsyncAwaitDemo.conditionalAsync('admin');
// 文件处理器演示
const processor = new AsyncFileProcessor();
const fileResults = await processor.processFiles(['package.json', 'README.md']);
console.log('文件处理结果:', fileResults);
} catch (error) {
console.error('演示执行失败:', error.message);
}
})();通过本节Node.js异步编程基础的学习,你已经掌握:
A: 现代Node.js开发推荐使用Promise或async/await。只有在使用老旧的API或需要与现有回调代码兼容时才使用回调。新代码应该优先选择async/await。
A: async/await是Promise的语法糖,功能相同但语法更简洁。async/await让异步代码看起来像同步代码,更易读易维护,是推荐的现代写法。
A: 使用try-catch块包围await语句。对于Promise.all等方法,也要用try-catch包围。建议在每个async函数中都有适当的错误处理。
A: Promise.all在任何一个Promise失败时就会失败,而Promise.allSettled会等待所有Promise完成(无论成功失败)。当你需要知道所有操作的结果时,使用allSettled。
A: 及时清理事件监听器,避免创建过多的Promise,合理使用Promise.race设置超时,不要在循环中创建大量异步操作而不控制并发数。
// 推荐的异步错误处理模式
async function robustAsyncOperation() {
try {
const result = await riskyOperation();
return result;
} catch (error) {
// 记录错误
console.error('操作失败:', error);
// 根据错误类型决定处理方式
if (error.code === 'NETWORK_ERROR') {
// 网络错误可以重试
return await retryOperation();
} else {
// 其他错误直接抛出
throw error;
}
}
}// 控制并发数量,避免资源耗尽
async function processWithConcurrencyLimit(items, processor, limit = 3) {
const results = [];
for (let i = 0; i < items.length; i += limit) {
const batch = items.slice(i, i + limit);
const batchResults = await Promise.all(
batch.map(item => processor(item))
);
results.push(...batchResults);
}
return results;
}"掌握异步编程是Node.js开发的核心技能。从回调函数到Promise再到async/await,每一种模式都有其适用场景。现代开发中,async/await是首选,但理解整个演进过程能让你更好地处理各种异步场景。接下来,让我们深入学习Node.js的核心模块!"