你的浏览器无法正常显示内容,请更换或升级浏览器!

Node.js 异步编程完全指南

tenfei
tenfei
发布于2026-03-22 23:36 阅读12次
Node.js 异步编程完全指南
# Node.js 异步编程完全指南 ## 前言 Node.js 是 JavaScript 运行时,采用非阻塞 I/O 模型,天生适合处理高并发场景。异步编程是 Node.js 的核心,也是开发者必须掌握的重要技能。本文将带你从回调函数开始,逐步深入到 Promise 和 async/await,全面掌握 Node.js 的异步编程模式。 ## 同步 vs 异步 首先理解同步和异步的区别: **同步代码:** ```javascript const fs = require("fs"); const data = fs.readFileSync("/etc/passwd"); console.log(data); console.log("后续代码"); ``` **异步代码:** ```javascript const fs = require("fs"); fs.readFile("/etc/passwd", (err, data) => { if (err) throw err; console.log(data); }); console.log("后续代码"); ``` 异步模式下,文件读取和后续代码会同时执行,这就是非阻塞 I/O 的威力。 ## 回调函数模式 回调是 Node.js 最基础的异步方式。 ```javascript const fs = require("fs"); fs.readFile("input.txt", "utf8", (err, data) => { if (err) { console.error("读取失败:", err); return; } console.log("内容:", data); }); fs.writeFile("output.txt", "Hello Node.js!", (err) => { if (err) throw err; console.log("写入成功"); }); ``` ### 回调地狱(Callback Hell) 多层嵌套的回调会导致代码难以维护: ```javascript fs.readFile("a.txt", (err, data) => { if (err) throw err; fs.readFile("b.txt", (err, data) => { if (err) throw err; fs.readFile("c.txt", (err, data) => { if (err) throw err; console.log(data); }); }); }); ``` ## Promise 模式 Promise 代表一个异步操作的最终结果。 ```javascript const fs = require("fs").promises; fs.readFile("input.txt", "utf8") .then(data => { console.log("读取成功:", data); return fs.writeFile("output.txt", data.toUpperCase()); }) .then(() => console.log("写入成功")) .catch(err => console.error("错误:", err)); ``` ### 链式调用 Promise 支持链式调用,告别回调地狱: ```javascript fetchUser(id) .then(user => fetchUserPosts(user.id)) .then(posts => fetchPostComments(posts[0].id)) .then(comments => console.log(comments)) .catch(err => console.error(err)); ``` ### Promise.all 并行执行 多个异步操作并行执行: ```javascript async function readAllFiles() { const [a, b, c] = await Promise.all([ fs.readFile("a.txt", "utf8"), fs.readFile("b.txt", "utf8"), fs.readFile("c.txt", "utf8") ]); return { a, b, c }; } ``` ## async/await 语法 async/await 是 Promise 的语法糖,让异步代码看起来像同步代码。 ```javascript const fs = require("fs").promises; async function processFile() { try { const data = await fs.readFile("input.txt", "utf8"); const upperData = data.toUpperCase(); await fs.writeFile("output.txt", upperData); console.log("处理完成"); } catch (err) { console.error("处理失败:", err); } } processFile(); ``` ### 并行 vs 串行 **串行执行(逐个):** ```javascript async function serial() { const a = await fs.readFile("a.txt"); const b = await fs.readFile("b.txt"); const c = await fs.readFile("c.txt"); } ``` **并行执行(同时):** ```javascript async function parallel() { const [a, b, c] = await Promise.all([ fs.readFile("a.txt"), fs.readFile("b.txt"), fs.readFile("c.txt") ]); } ``` ### 错误处理 ```javascript async function safeOperation() { try { const result = await riskyOperation(); return result; } catch (err) { console.error("操作失败:", err.message); throw err; } } ``` ## 实际应用场景 ### 文件操作 ```javascript const fs = require("fs").promises; const path = require("path"); async function copyDirectory(src, dest) { await fs.mkdir(dest, { recursive: true }); const entries = await fs.readdir(src, { withFileTypes: true }); for (const entry of entries) { const srcPath = path.join(src, entry.name); const destPath = path.join(dest, entry.name); if (entry.isDirectory()) { await copyDirectory(srcPath, destPath); } else { await fs.copyFile(srcPath, destPath); } } } ``` ### HTTP 请求 ```javascript const axios = require("axios"); async function fetchUserData(userIds) { const requests = userIds.map(id => axios.get(`https://api.example.com/users/${id}`) ); const responses = await Promise.allSettled(requests); return responses .filter(r => r.status === "fulfilled") .map(r => r.value.data); } ``` ### 数据库操作 ```javascript const { Pool } = require("pg"); const pool = new Pool({ connectionString: process.env.DATABASE_URL }); async function getUserWithPosts(userId) { const client = await pool.connect(); try { await client.query("BEGIN"); const userResult = await client.query( "SELECT * FROM users WHERE id = $1", [userId] ); const postsResult = await client.query( "SELECT * FROM posts WHERE user_id = $1", [userId] ); await client.query("COMMIT"); return { user: userResult.rows[0], posts: postsResult.rows }; } catch (err) { await client.query("ROLLBACK"); throw err; } finally { client.release(); } } ``` ## 最佳实践 1. 优先使用 async/await:代码更清晰易读 2. 正确处理错误:使用 try/catch 捕获异常 3. 避免串行等待:需要多个异步操作时考虑并行 4. 使用 Promise.all:并行执行独立任务 5. 合理使用 Promise.allSettled:不阻塞其他任务 6. 注意内存泄漏:确保释放资源(如数据库连接) ## 总结 Node.js 的异步编程经历了回调 -> Promise -> async/await 的演进。async/await 已成为现代 Node.js 开发的主流方式,它让异步代码的书写和阅读都更加自然。掌握异步编程是成为 Node.js 高手的关键,希望这篇文章能帮助你在实际项目中更好地运用这些技术。

1

0

文章点评
暂无任何评论
Copyright © from 2021 by namoer.com
458815@qq.com QQ:458815
蜀ICP备2022020274号-2