JavaScript异步编程简介
\n\nJavaScript是一种单线程编程语言。这意味着在任意时刻只能执行一个操作。然而,如果所有操作都按顺序执行,浏览器在从服务器加载数据或读取文件时就会“卡死”。这正是异步编程发挥作用的地方。
\n\n异步编程允许执行耗时操作(API请求、文件读取、定时器)而不阻塞主执行线程。代码不会等待任务完成,而是继续执行,结果稍后处理。这是创建快速响应式Node.js应用程序的关键概念。
\n\n在本指南中,我们将介绍异步编程的三种主要方法:回调、Promise和async/await语法。您将学习如何正确处理异步代码并避免初学者的常见错误。
1. 回调(Callbacks):异步的基础
\n\n回调(callback)是一个作为参数传递给另一个函数的函数,在异步操作完成后被调用。这是JavaScript中最古老、最基本的异步处理方式。
\n\nsetTimeout示例
\n\n内置函数setTimeout是异步操作的经典示例。它接受一个回调和一个以毫秒为单位的延迟:
console.log('开始');\n\nsetTimeout(() => {\n console.log('2秒过去了');\n}, 2000);\n\nconsole.log('结束');\n\n// 输出:\n// 开始\n// 结束\n// 2秒过去了\n\n请注意:“结束”在回调消息之前输出。这就是异步——代码不会等待setTimeout完成。
“回调地狱”问题
\n\n当有大量嵌套的异步操作时,代码变得难以阅读。这种现象称为“回调地狱”(Callback Hell):
\n\nfs.readFile('file1.txt', (err, data1) => {\n if (err) throw err;\n fs.readFile('file2.txt', (err, data2) => {\n if (err) throw err;\n fs.readFile('file3.txt', (err, data3) => {\n if (err) throw err;\n console.log(data1, data2, data3);\n });\n });\n});\n\n这样的代码难以维护和调试。幸运的是,现代JavaScript提供了更优雅的解决方案。
\n\n2. Promise:优雅的异步处理
\n\nPromise(承诺)是一个表示异步操作结果的对象。Promise可以处于以下三种状态之一:
\n\n- \n
- Pending(待定)——初始状态,操作尚未完成 \n
- Fulfilled(已完成)——操作成功完成 \n
- Rejected(已拒绝)——操作以错误结束 \n
创建和使用Promise
\n\nconst myPromise = new Promise((resolve, reject) => {\n setTimeout(() => {\n const success = true;\n if (success) {\n resolve('数据已获取');\n } else {\n reject('获取数据出错');\n }\n }, 2000);\n});\n\nmyPromise\n .then(result => {\n console.log(result); // "数据已获取"\n })\n .catch(error => {\n console.error(error); // "获取数据出错"\n })\n .finally(() => {\n console.log('操作完成');\n });\n\nPromise链式调用(Chaining)
\n\nPromise可以链式调用,从而避免“回调地狱”:
\n\nfunction readFile(filename) {\n return new Promise((resolve, reject) => {\n fs.readFile(filename, 'utf8', (err, data) => {\n if (err) reject(err);\n else resolve(data);\n });\n });\n}\n\nreadFile('file1.txt')\n .then(data1 => {\