帝国网站管理系统如何做商城网页小游戏网站建设
异步编程基础
本文主要介绍回调函数,Promise,aysnc/wait这三种异步机制,顺便说说axios,还有不要和我一样弄混ajax与异步的关系,正常走学校教学路线的人,可能第一个接触的就是ajax,刚好又不懂,所以可能和我一样弄混。除上述知识点,其他都是凑字数的。
注意AJAX不是前端异步的代名词
反正我学的时候老是容易搞混
 
混淆原因
早期 “AJAX” 一词被广泛用于指代 “异步网络请求”,因为在 AJAX 诞生初期(2005 年左右),它是前端实现异步通信的主要方式,因此很多人将 “异步” 与 “AJAX” 直接关联,AJAX 只是异步编程在 “浏览器与服务器通信” 场景下的应用
前端异步机制分类:通用机制与应用场景
一、异步编程通用机制(按实现方式分类)
| 机制类型 | 核心原理 | 典型实现 | 优缺点 | 
|---|---|---|---|
| 回调函数 | 通过函数参数传递异步结果,异步任务完成后调用回调函数 | setTimeout、XMLHttpRequest 旧版 | - 简单直接 - 缺点:回调地狱、代码可读性差  | 
| Promise | 用状态机管理异步操作(pending/fulfilled/rejected),支持链式调用 | fetch()、Promise.resolve() | - 避免回调嵌套 - 统一错误处理( .catch())- 代码更清晰  | 
| async/await | Promise 的语法糖,以同步写法处理异步,自动返回 Promise | async function + await | - 最接近同步代码的写法 - 错误处理用 try...catch,更符合直觉 | 
| Generator | 通过迭代器(Iterator)分段执行异步任务,需手动调用 next() 推进流程 | function* gen() { yield ... } | - 控制粒度更细 - 缺点:需手动管理流程,现代开发中较少使用  | 
二、异步机制应用场景(按功能场景分类)
| 场景类型 | 核心功能 | 技术实现 | 典型案例 | 
|---|---|---|---|
| 网络通信 | 浏览器与服务器的异步数据交互,不阻塞页面 | fetch、XMLHttpRequest、WebSocket | - 动态加载数据(如商品列表) - 实时聊天WebSocket(异步双向通信)  | 
| 定时任务 | 按指定时间间隔执行异步操作 | setTimeout、setInterval | - 轮询获取数据(如天气更新) - 动画帧控制( requestAnimationFrame) | 
| 用户交互 | 响应鼠标、键盘等用户操作,异步执行回调 | 事件监听(addEventListener) | - 按钮点击、滚动加载更多 - 表单实时验证  | 
| 并行计算 | 开启后台线程处理密集计算,不阻塞主线程(UI 渲染) | Web Worker、SharedWorker | - 图片处理、大数据排序 - 游戏物理引擎计算  | 
| 文件操作 | 异步读取/写入文件(主要在 Node.js 环境) | fs.readFile、fs.writeFile | - 读取配置文件 - 写入日志数据  | 
1. 异步编程有什么用?
有点后端基础的都知道,异步是在多线程学习时,才涉及到的概念,那么前端的这个异步有什么作用?
这里敲黑板!!!
前端的异步它并非解决多线程问题,它只是在表面上达到了多线程一样的效果,而是为了在单线程环境下实现非阻塞操作。
JavaScript主线程单线程的特性决定了同步操作会阻塞渲染,所以提出了异步的概念解决这个问题
 
JavaScript 是一种单线程语言,运行在浏览器的主线程中。这意味着在任何时刻,JavaScript 代码只能在一个线程上运行。无论是同步代码还是异步代码,它们都是在同一个线程上执行的。
总之,别把前端的异步和后端的异步扯上一点关系,当一个全新的东西去学就好了。
举个前端异步例子:
前端同步就像你洗澡,得先等热水器把水烧热,才能开始洗。要是热水器坏了,或者水烧得很慢,你就只能干等着,啥也干不了。
前端异步就好比你一边烧热水,一边看电视。热水烧着就烧着,你也不用一直盯着,可以先做别的事。等水烧好了,你再洗澡就行。这样,你的时间就被充分利用了,不会因为等待热水而浪费时间,整个过程也更高效。
2. 异步机制
异步机制 :允许在等待I/O(网络请求/文件读取)时释放主线程,保持页面渲染与处理流畅。它的核心目的是让程序在等待某个任务完成时,能够继续执行其他任务,而不是像同步代码那样一直阻塞等待。
所有异步机制最终都基于浏览器的 事件循环(Event Loop) 机制执行,这是 JS 异步编程的核心基础。
3. 前端有几种异步机制
前端中常见的异步机制包括回调函数、Promise、async/await、和 Generator。其中,Promise 和 async/await 是目前最常用和推荐的异步处理方式。
本文重点介绍前四种异步机制,最后一种说实话我还没真正用过。
3.1 回调函数(Callback)
回调函数是最传统的异步处理方式,通过将一个函数作为参数传递给另一个函数,并在异步操作完成时调用这个回调函数。
示例代码
//函数定义:fetchData 函数定义时,接受一个函数式的参数 callback。这个callback并没有具体定义,和普通参数一样,只是提供一个位置。
//这个参数是一个函数,意味着 fetchData 可以在执行过程中调用这个传入的函数。
function fetchData(callback) {//这里是故意的延时操作,模拟服务器2秒后加载回数据setTimeout(() => {console.log("数据加载完成!");callback("数据");}, 2000);
}fetchData((data) => {console.log("接收到数据:", data);
});
 
回调体现
函数定义:在 fetchData 函数内部,使用 setTimeout 模拟了一个异步操作(例如,从服务器加载数据)。当这个异步操作完成时(即 2 秒后),通过 callback(“数据”) 调用了传入的回调函数,并传递了 “数据” 作为参数。
回调函数的使用:在 fetchData 函数调用时,
 传入了一个箭头函数 (data) => { console.log("接收到数据:", data); } 作为回调函数。
 所以这个fetchData执行的步骤其实是这样的
 1.进入setTimeOut函数内部
 2.延时2秒
 4. 输出"数据加载完成"日志
 5.执行callback函数参数,而此时callback函数参数是(data) => { console.log(“接收到数据:”, data); }
 6. 输出"接收到数据:数据"日志
 
顺带解释一下这里的箭头函数
箭头函数(基础知识点复习)
箭头函数是ES6引入的简洁函数语法,用=>符号定义,通常省略function关键字和return,适用于单行表达式或需要绑定外层this的场景。
例如传统函数:
 function(a, b) { return a + b; }
 可简化为箭头函数:
 (a, b) => a + b
关键特性:
- 无独立
this,继承父级作用域的this - 不能用作构造函数(无
prototype属性) - 适合回调函数或方法缩写
 
回调特点总结
- 简单直接,适用于简单的异步操作。
 - 但容易出现“回调地狱”(Callback Hell),即嵌套过多的回调函数,代码难以维护。
 
3.2 Promise
Promise 是一种更现代的异步处理方式,它代表了一个异步操作的最终完成(或失败)及其结果值,其实写它的时候也会使用回调函数,只不过一个传统回调函数实现异步更像嵌套使用,后者是链式调用,代码可读性会好一丢丢,并且Promise有一定的定义和方法,方便处理异常情况。
 
注意这个目前Promise并没有特别合适的中文翻译,所以和别人讨论异步涉及它时,直接说这个单词就好了。
Promise状态
Promise 有三种状态:
pending:初始状态,既不是成功也不是失败。
 fulfilled:操作成功完成。
 rejected:操作失败,(Promise任何一个环节出现错误都会切换到这个状态,当然也可以手动reject让Promise切换成rejected状态)
状态一旦改变(从 pending 变为 fulfilled 或 rejected),就会被固化,不会再变化。
Promise状态处理
Promise 提供 .then()、.catch() 和 .finally() 处理结果:
- .then() 可处理 fulfilled 或 rejected 状态(通过第二个回调参数,可以忽略处理rejected状态的处理,大多数人更习惯使用.catch来处理rejected状态)。
 - .catch() 是专门处理 rejected 状态的语法糖(等价于 .then(null, onRejected))。
 - .finally() 无论状态如何都会执行,用于清理操作。
 
示例代码:
function fetchData() {return new Promise((resolve, reject) => {setTimeout(() => {console.log("数据加载完成!");resolve("数据");// 如果出错可以用 reject("错误信息");}, 2000);});
}fetchData().then((data) => {console.log("接收到数据:", data);}).catch((error) => {console.error("发生错误:", error);});
 
Promise特点总结:
- 避免了回调地狱,代码更加清晰。
 - 提供了错误处理机制(通过 
.catch())。 - 可以通过 
Promise.all()等方法同时处理多个异步操作。 
3.3 async/await
async 和 await 是 ES2017(ES8)引入的 JavaScript 语法,用于简化 Promise 的使用,让异步代码看起来更像同步代码。它们本质上是 Promise 的语法糖,但提供了更直观的写法。
用我自己的角度来理解,你想让异步操作,就在函数前面加个await,如果某个函数里加了await,那就必须使用aysnc保证它异步操作生效。并且await要使用try和catch进行异常捕获。
哪里需要等待异步结果,就在哪里加 await;加了 await 的函数必须用 async 修饰;为了安全,用 try…catch 捕获可能的错误。
aysnc
async 用于声明一个异步函数,它有两个特点:
- 自动返回 Promise:无论函数内部是否显式返回 Promise,async 函数的返回值都会被包装成 Promise。
 - 支持 await:async 函数内部可以使用 await 关键字等待 Promise 完成。
 
await
await 只能在 async 函数内部使用,它的作用是:
- 暂停函数执行:等待 Promise 被解决(fulfilled 或 rejected)。
 - 返回 Promise 的结果:如果 Promise 成功,则返回其结果值;如果失败,则抛出错误(需用 try…catch 捕获)。
 
示例代码:
// 模拟一个异步操作(如网络请求)
function simulateNetworkRequest() {console.log("开始请求数据...");// 返回一个 Promise,表示异步操作return new Promise((resolve) => {// 使用 setTimeout 模拟 2 秒的网络延迟setTimeout(() => {console.log("服务器已返回数据!");resolve("用户信息和文章列表"); // 数据加载完成,传递结果}, 2000);});
}// 使用 async 声明异步函数
async function fetchData() {console.log("进入 fetchData 函数");// await 会暂停当前函数的执行,等待 Promise 完成const result = await simulateNetworkRequest();// 这行代码会在 Promise 成功后才执行console.log("fetchData 函数继续执行");return result;
}// 主函数
async function main() {console.log("程序开始执行");try {console.log("等待数据加载...");// 调用异步函数并等待结果const data = await fetchData();// 这行代码会在 fetchData 完全执行完毕后才运行console.log("成功获取数据:", data);} catch (error) {console.error("获取数据失败:", error);}console.log("程序执行结束");
}// 启动主函数
main();
 
aysnc/wait特点总结:
- 代码更简洁,更接近同步代码的写法。
 - 使用 
try...catch可以方便地捕获错误。 - 需要与 Promise 结合使用。
 
3.4 Generator(生成器)
Generator 是一种可以暂停和恢复执行的函数,虽然它本身不是直接用于异步操作,但可以通过手动控制暂停和恢复来实现异步效果。不过,Generator 的使用相对复杂,且不如 async/await 方便。
示例代码:
function* fetchData() {console.log("开始加载数据");yield new Promise((resolve) => {setTimeout(() => {console.log("数据加载完成!");resolve("数据");}, 2000);});
}const generator = fetchData();
const promise = generator.next().value;
promise.then((data) => {console.log("接收到数据:", data);
});
 
特点总结:
- 可以暂停和恢复函数执行。
 - 需要手动管理暂停点和恢复逻辑。
 - 使用场景较少,通常被 
async/await替代。 
异步实现方法总结
前端中常见的异步机制包括回调函数、Promise、async/await和 Generator已经基本介绍了一遍。说实话没有实践,这些理论都很难理解,就算理解了也真得很难形象地描述出来。
 其中,Promise 和 async/await 是目前最常用和推荐的异步处理方式,因为它们提供了更简洁、更易读的代码风格和强大的错误处理机制。
4 axios:基于Promise的HTTP客户端
前文已经说过Promise和async/await` 是目前最常用和推荐的异步处理方式,这么常用又好用的功能自然有人会想办法使用技术和它进行对接。
axios是一个流行的基于Promise的HTTP客户端,可以用于浏览器和Node.js环境。它提供了丰富的功能,如拦截请求和响应、取消请求、自动转换JSON数据等。
4.1 axios的基本用法
axios的核心API返回Promise,因此可以与async/await无缝集成:
// GET请求
axios.get('/api/users').then(response => console.log(response.data)).catch(error => console.error(error));
// POST请求
axios.post('/api/users', { name: 'John' }).then(response => console.log('创建成功:', response.data)).catch(error => console.error('创建失败:', error));
 
4.2 axios与async/await的结合
axios与async/await结合使用可以简化异步请求处理:
async function getUserData(userId) {try {const userResponse = await axios.get(`/api/users/${userId}`);const user = userResponse.data;const postsResponse = await axios.get(`/api/users/${userId}/posts`);const posts = postsResponse.data;return { user, posts };} catch (error) {console.error('获取数据失败:', error);throw error;}
}
 
4.3 axios的优势
- Promise基础:所有请求都返回Promise,可以与async/await完美结合
 - 拦截器:可以拦截请求和响应,添加自定义逻辑(如认证、日志记录)
 - 取消请求:支持请求取消,避免不必要的处理
 - 自动转换JSON:自动将响应数据转换为JavaScript对象
 - 浏览器兼容性:支持老版本浏览器,提供polyfill
 
5 技术对比与选择指南
5.1 Promise与async/await的区别
| 特性 | Promise | async/await | 
|---|---|---|
| 语法 | 链式调用 .then() | 类同步代码 | 
| 错误处理 | .catch() | try/catch | 
| 可读性 | 可能形成回调地狱 | 更接近自然语言 | 
| 适用场景 | 简单异步操作 | 复杂异步流程 | 
| 基础 | 是异步处理的基础 | 建立在Promise之上 | 
5.2 axios与原生fetch的对比
| 特性 | axios | fetch | 
|---|---|---|
| Promise基础 | 是 | 是 | 
| 自动JSON转换 | 是 | 否 | 
| 拦截器 | 支持 | 不支持 | 
| 错误处理 | 自动处理网络错误 | 需要手动检查 | 
| 浏览器兼容 | 广泛支持 | 现代浏览器 | 
| 取消请求 | 支持 | 需要polyfill | 
5.3 链式调用与同步异步的结合
在实现异步链式调用时,需要考虑:
- 同步链式调用:方法依次执行,每个方法返回this
 - 异步链式调用:方法中包含异步操作,需要特殊处理执行顺序
 - Promise链式调用:使用
.then()连接多个异步操作 - async/await链式调用:使用await等待异步操作完成
 
6. 最佳实践与注意事项
6.1 异步编程的最佳实践
- 错误处理:始终处理异步操作中的错误,特别是在使用async/await时
 - 并行操作:对于不依赖彼此的异步操作,使用Promise.all并行执行
 - 取消机制:对于长时间运行的操作,实现取消机制避免资源浪费
 - 避免过度使用await:对于并行操作,await会串行化执行,影响性能
 
6.2 性能优化建议
- 缓存结果:对于重复的异步操作,考虑缓存结果
 - 限制并发:对于大量异步操作,限制并发数量避免资源耗尽
 - 使用Web Workers:对于CPU密集型操作,考虑使用Web Workers
 - 合理使用Promise.allSettled:当需要等待多个操作完成而不关心个别失败时
 
6.3 代码组织建议
- 分离异步逻辑:将异步操作封装在单独的函数中
 - 使用中间件模式:对于复杂的异步流程,考虑使用中间件模式
 - 避免嵌套:使用async/await减少回调嵌套
 - 文档注释:为异步函数添加清晰的文档注释,说明返回的Promise状态
 
7 异步编程总结与未来展望
异步编程是现代Web开发的核心技能,Promise、async/await、axios和链式调用等技术共同构成了JavaScript异步编程的完整生态。这些技术各有优势,合理组合使用可以构建出高效、可维护的应用程序。
 随着JavaScript语言的发展,异步编程模型将继续演进。异步迭代器、异步生成器等新特性为异步编程提供了更多可能性。同时,TypeScript等工具也为异步代码提供了更好的类型支持,进一步提高了开发效率和代码可靠性。
 掌握这些异步编程技术,不仅能够解决当前的开发挑战,也为应对未来更复杂的异步场景奠定了坚实基础。通过不断实践和总结,开发者可以形成自己高效的异步编程模式,构建出更优秀的Web应用。
