ES6 promise-try-catch-模块化开发
一、Promise:异步编程解决方案
Promise 是 ES6 引入的异步编程规范,主要用于解决 “回调地狱” 问题,让异步代码的逻辑更清晰、更易维护。
1. 核心概念与状态
- 本质:Promise 是一个构造函数,用于封装异步操作,并可以获取操作的成功 / 失败结果。
- 三种状态(状态一旦改变,不可逆):
pending
:初始状态,异步操作未完成。fulfilled
(resolved):异步操作成功,状态从pending
转为fulfilled
。rejected
:异步操作失败,状态从pending
转为rejected
。
- 核心方法:
- 构造函数参数:接收一个函数
(resolve, reject) => {}
,resolve
用于成功时传递结果,reject
用于失败时传递错误。 - 实例方法:
then()
处理成功结果,catch()
处理失败错误。
- 构造函数参数:接收一个函数
2. 基本用法(以 AJAX 请求为例)
javascript
运行
// 1. 创建 Promise 实例,封装异步操作(AJAX 请求)
function requestData(url) {return new Promise((resolve, reject) => {$.ajax({url: url,dataType: "json",success: (res) => {resolve(res); // 成功:调用 resolve 传递结果},error: (err) => {reject(err); // 失败:调用 reject 传递错误}});});
}// 2. 调用 Promise,处理结果
requestData("arr.txt").then((res) => {console.log("请求成功:", res); // 接收 resolve 传递的结果}).catch((err) => {console.log("请求失败:", err); // 接收 reject 传递的错误});
3. 解决回调地狱
传统多层异步嵌套(如 “请求 1 成功后请求 2,请求 2 成功后请求 3”)会形成 “回调地狱”,Promise 可通过 then()
链式调用解决:
javascript
运行
// 链式调用:依次执行 3 个 AJAX 请求
requestData("1.txt").then((res1) => {console.log("请求1结果:", res1);return requestData("2.txt"); // 返回新的 Promise,进入下一个 then}).then((res2) => {console.log("请求2结果:", res2);return requestData("3.txt");}).then((res3) => {console.log("请求3结果:", res3);}).catch((err) => {console.log("任意一步失败:", err); // 捕获所有步骤的错误});
4. Promise 静态方法
方法 | 功能描述 |
---|---|
Promise.all([p1, p2, p3]) | 接收多个 Promise 实例,所有实例都成功才返回成功结果数组;任意一个失败则直接返回失败。 |
Promise.race([p1, p2, p3]) | 接收多个 Promise 实例,谁先完成(成功 / 失败) 就返回谁的结果,忽略其他实例。 |
- 示例(
Promise.all
批量请求):javascript
运行
// 同时请求 2 个接口,全部成功后处理结果 Promise.all([requestData("1.txt"),requestData("2.txt") ]).then(([res1, res2]) => { // 解构结果数组console.log("请求1结果:", res1);console.log("请求2结果:", res2);}).catch((err) => {console.log("至少一个请求失败:", err);});
5. 关键面试点:Promise 是同步还是异步?
- 结论:Promise 构造函数内部的代码是同步执行的,但
resolve
/reject
触发的then()
/catch()
回调是异步执行的(放入微任务队列)。 - 示例:
javascript
运行
console.log(1); let p = new Promise((resolve) => {console.log(2); // 同步执行resolve(); // 触发 then 回调(异步) }); p.then(() => {console.log(4); // 异步执行(微任务) }); console.log(3); // 同步执行 // 输出顺序:1 → 2 → 3 → 4
二、try-catch:异常捕获
try-catch
语句用于捕获代码执行中的异常(错误),避免程序因报错而中断,同时可以自定义错误处理逻辑。
1. 基本语法
javascript
运行
try {// 可能出错的代码(尝试执行)let data = '{"name":"XX";"age":100}'; // 格式错误的 JSONlet newData = JSON.parse(data); // 此处会报错console.log(newData.name);
} catch (error) {// 捕获到错误时执行(error 是错误信息对象)console.log("执行出错:", error.message); // 输出:Unexpected token ; in JSON at position 10
} finally {// 无论是否出错,都会执行(可选,常用于清理资源)console.log("无论对错,我都会执行");
}
2. 注意事项
- 性能问题:
try-catch
会轻微影响代码执行效率,避免在高频执行的逻辑(如循环)中使用。 - 异步错误捕获限制:
try-catch
无法捕获异步操作(如setTimeout
、AJAX)中的错误,需在异步回调内部单独捕获。javascript
运行
// 错误示例:无法捕获 setTimeout 内的错误 try {setTimeout(() => {console.log(a); // a 未定义,会报错,但 try-catch 捕获不到}, 100); } catch (err) {console.log("捕获不到错误:", err); }// 正确示例:在异步内部捕获 setTimeout(() => {try {console.log(a);} catch (err) {console.log("捕获到错误:", err);} }, 100);
三、ES6 模块化开发
模块化是将代码拆分为独立文件(模块),通过 export
(导出)和 import
(导入)实现模块间的依赖管理,解决全局变量污染、代码复用等问题。
1. 核心语法
(1)导出模块(export
)
在模块文件(如 utils.js
)中,通过 export
暴露需要对外提供的变量、函数或对象:
javascript
运行
// utils.js
let PI = 3.14;
function sum(a, b) {return a + b;
}
const user = { name: "Alice", age: 20 };// 方式1:按需导出(可导出多个)
export { PI, sum, user };// 方式2:默认导出(只能有一个默认导出,导入时可自定义名称)
export default function multiply(a, b) {return a * b;
}
(2)导入模块(import
)
在使用模块的文件中,通过 import
引入其他模块的内容,需在 <script>
标签中添加 type="module"
:
html
预览
<!-- index.html -->
<script type="module">// 1. 导入按需导出的内容(名称必须与导出一致)import { PI, sum, user } from "./utils.js";console.log(PI); // 3.14console.log(sum(1, 2)); // 3// 2. 导入默认导出的内容(可自定义名称,如 "mult")import mult from "./utils.js";console.log(mult(2, 3)); // 6// 3. 批量导入(给模块起别名 "utils")import * as utils from "./utils.js";console.log(utils.PI); // 3.14console.log(utils.sum(3, 4)); // 7
</script>
2. 注意事项
- 模块文件路径必须完整(如
./utils.js
,不能省略.js
)。 - 模块内的变量、函数默认是局部的,只有通过
export
导出后才能被其他模块访问。 - 浏览器环境中,模块脚本会自动开启严格模式(
use strict
)。
四、async/await:异步代码的 “语法糖”
async/await
是 ES2017(ES8)引入的语法,基于 Promise 实现,让异步代码的写法更接近同步代码,进一步简化异步逻辑。
1. 核心语法
async
函数:- 用
async
修饰的函数,返回值会自动封装为 Promise 对象(若返回普通值,等同于return Promise.resolve(普通值)
)。 - 内部可使用
await
关键字。
- 用
await
关键字:- 只能在
async
函数内部使用,用于 “等待” Promise 对象的结果(成功 / 失败)。 - 等待期间会暂停
async
函数的执行,但不会阻塞整个线程(底层是 Promise 的微任务)。
- 只能在
2. 基本用法(以 AJAX 请求为例)
javascript
运行
// 1. 复用之前的 Promise 异步函数
function requestData(url) {return new Promise((resolve, reject) => {$.ajax({url: url,dataType: "json",success: (res) => resolve(res),error: (err) => reject(err)});});
}// 2. 用 async/await 编写异步逻辑
async function getData() {try {// 等待 Promise 成功,直接获取结果(无需 then)let res1 = await requestData("1.txt");console.log("请求1结果:", res1);let res2 = await requestData("2.txt");console.log("请求2结果:", res2);return "所有请求完成";} catch (err) {// 捕获所有 await 中的错误(等同于 Promise 的 catch)console.log("请求失败:", err);}
}// 3. 调用 async 函数(返回 Promise,可加 then 处理)
getData().then((msg) => {console.log(msg); // 所有请求完成
});
3. 优势与注意事项
- 优势:逻辑清晰,避免
then
链式调用的嵌套,代码可读性更高。 - 注意事项:
await
只能等待 Promise 对象,若等待普通值,会直接返回该值(无等待效果)。async
函数内部的错误需用try-catch
捕获(否则会导致 Promise 变为rejected
状态,需用catch
处理)。- 若需并行执行多个异步操作,仍需使用
Promise.all
(await
默认是串行执行)。