编程入门
Java 入门教程:从零开始学 Java
零基础学 JavaScript 异步编程:从回调到 async/await
Rust 所有权与借用机制入门
Go 语言零基础教程 - 并发编程入门
Go 语言入门教程:并发编程基础(Goroutine 与 Channel)
Python 零基础入门:从第一行代码到独立编程
本站点使用 MrDoc 构建
-
+
零基础学 JavaScript 异步编程:从回调到 async/await
> 📘 本文是「编程入门」系列教程之一,面向零基础读者,带你从回调地狱一路走到 async/await 的优雅世界。 ## 学习目标 读完本文,你将能够: - 理解**同步**与**异步**的区别,知道为什么 JavaScript 需要异步 - 掌握 **Promise** 的三种状态和基本用法 - 熟练使用 **async/await** 编写清晰的异步代码 - 识别并避免常见的异步编程陷阱 ## 前置知识 - JavaScript 基本语法(变量、函数、条件判断) - 了解什么是函数调用和返回值 - 知道浏览器/Node.js 的基本运行环境 不需要任何异步编程经验——这正是本文要教你的! --- ## 一、为什么需要异步? JavaScript 是**单线程**语言,同一时间只能做一件事。如果一段代码需要等待(比如网络请求、读取文件),整个程序就会"卡住"——这就是**同步阻塞**。  上面的图展示了同步和异步的区别: - **同步**:任务 A 完成后才能开始任务 B,等待时间被浪费 - **异步**:任务 A 开始等待后,立刻执行任务 B,等 A 的结果回来再处理 现实生活中的例子:你烧水的时候不需要盯着水壶,可以去切菜——等水开了再回来处理。这就是异步的思维。 --- ## 二、回调函数:异步的起点 最原始的异步写法是**回调函数**——把"等结果回来后要做的事"作为参数传进去: ```javascript console.log("开始点餐"); setTimeout(function() { console.log("汉堡做好了!"); }, 2000); console.log("先喝口水"); ``` 输出顺序:开始点餐 → 先喝口水 → 汉堡做好了! 回调本身没问题,但当你需要**多个异步操作按顺序执行**时,代码就会层层嵌套: ```javascript getData(function(a) { getMoreData(a, function(b) { getEvenMore(b, function(c) { // 这就是传说中的"回调地狱" 🌋 console.log(c); }); }); }); ``` 这种金字塔式的代码被称为 **回调地狱(Callback Hell)**,难以阅读和维护。我们需要更好的方案。 --- ## 三、Promise:告别回调地狱 ### 3.1 什么是 Promise? Promise 是一个代表"未来某个值"的对象。它有三种状态:  - **Pending(等待中)**:初始状态,还没有结果 - **Fulfilled(已完成)**:操作成功,拿到了结果 - **Rejected(已拒绝)**:操作失败,拿到了错误 **关键规则:状态只能改变一次**,从 Pending 变为 Fulfilled 或 Rejected 后就不可逆。 ### 3.2 创建 Promise ```javascript const myPromise = new Promise(function(resolve, reject) { // 模拟异步操作 setTimeout(function() { const success = true; if (success) { resolve("操作成功!"); // 状态 → Fulfilled } else { reject("出错了!"); // 状态 → Rejected } }, 1000); }); ``` ### 3.3 使用 Promise ```javascript myPromise .then(function(result) { console.log(result); // "操作成功!" }) .catch(function(error) { console.error(error); // "出错了!" }); ``` ### 3.4 链式调用 Promise 最大的优势是**链式调用**,让异步代码从"金字塔"变成"直线": ```javascript fetch("https://api.example.com/users/1") .then(function(response) { return response.json(); // 返回新 Promise }) .then(function(user) { return fetch(user.posts_url); }) .then(function(response) { return response.json(); }) .then(function(posts) { console.log(posts); }) .catch(function(error) { console.error("某一步出错了:", error); }); ``` 比回调地狱清晰多了!但还能更好—— --- ## 四、async/await:让异步像同步一样好读 ### 4.1 基本语法 `async/await` 是 Promise 的**语法糖**,让你用同步的写法写异步代码:  ```javascript async function getUserPosts() { try { const response = await fetch("https://api.example.com/users/1"); const user = await response.json(); const postsRes = await fetch(user.posts_url); const posts = await postsRes.json(); console.log(posts); } catch (error) { console.error("出错了:", error); } } getUserPosts(); ``` ### 4.2 关键规则 | 语法 | 含义 | |------|------| | `async function` | 声明一个异步函数,它**总是返回 Promise** | | `await` | 暂停执行,等待 Promise 完成后拿到结果 | | `try/catch` | 替代 `.catch()`,捕获异步错误 | ### 4.3 箭头函数也行 ```javascript const getData = async () => { const result = await someAsyncOperation(); return result; }; ``` ### 4.4 并行执行多个异步操作 如果多个异步操作之间没有依赖关系,用 `Promise.all()` 让它们同时跑: ```javascript async function loadDashboard() { const [users, posts, comments] = await Promise.all([ fetch("/api/users").then(r => r.json()), fetch("/api/posts").then(r => r.json()), fetch("/api/comments").then(r => r.json()), ]); console.log(users, posts, comments); } ``` 这样比逐个 `await` 快得多! --- ## 五、动手练习 ### 练习 1:模拟异步延迟 用 Promise 封装一个 `delay` 函数: ```javascript function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function main() { console.log("等 2 秒..."); await delay(2000); console.log("2 秒到了!"); } main(); ``` ### 练习 2:顺序加载 用 async/await 按顺序加载 3 个接口,并在每个加载完成后打印: ```javascript async function loadInOrder() { const urls = [ "https://jsonplaceholder.typicode.com/users/1", "https://jsonplaceholder.typicode.com/users/2", "https://jsonplaceholder.typicode.com/users/3", ]; for (const url of urls) { const res = await fetch(url); const data = await res.json(); console.log(data.name); } } loadInOrder(); ``` ### 练习 3:错误处理 给下面的代码添加 try/catch,让它在网络错误时不崩溃: ```javascript async function safeFetch(url) { try { const res = await fetch(url); if (!res.ok) throw new Error(`HTTP ${res.status}`); return await res.json(); } catch (err) { console.error("请求失败:", err.message); return null; } } ``` --- ## 六、常见新手误区 ### ❌ 误区 1:忘记 await ```javascript // 错误:result 是 Promise 对象,不是实际数据 const result = fetch(url); // 正确: const result = await fetch(url); ``` ### ❌ 误区 2:在普通函数里用 await ```javascript // 错误:await 只能在 async 函数内使用 function getData() { const res = await fetch(url); // SyntaxError! } // 正确: async function getData() { const res = await fetch(url); // ✅ } ``` ### ❌ 误区 3:过度使用 await 导致性能浪费 ```javascript // 慢:3 个请求串行,总耗时 = a + b + c const a = await fetchA(); const b = await fetchB(); const c = await fetchC(); // 快:3 个请求并行,总耗时 = max(a, b, c) const [a, b, c] = await Promise.all([ fetchA(), fetchB(), fetchC() ]); ``` ### ❌ 误区 4:不处理错误 ```javascript // 危险:如果请求失败,整个程序可能崩溃 async function getData() { const res = await fetch(url); return res.json(); } // 安全:总是处理可能的错误 async function getData() { try { const res = await fetch(url); return await res.json(); } catch (err) { console.error(err); return null; } } ``` --- ## 七、下一步 恭喜你掌握了 JavaScript 异步编程的核心!接下来可以探索: 1. **Promise 进阶**:`Promise.race()`、`Promise.any()`、`Promise.allSettled()` 2. **事件循环(Event Loop)**:理解微任务和宏任务的执行顺序 3. **生成器(Generator)**:另一种暂停执行的机制 4. **真实项目**:用 async/await 封装 API 请求层 > 💡 记住:async/await 只是 Promise 的语法糖,理解 Promise 才是根本。两个都要会!
admin
2026年5月16日 19:05
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文档(打印)
分享
链接
类型
密码
更新密码