一、传统回调函数与Promise封装对比
1. 传统回调函数示例
javascript
// 原始异步函数(带回调)
function dynamicFunc(cb) {
setTimeout(() => {
console.log('1s 后显示');
cb();
}, 1000);
}
const callback = () => {
console.log('在异步结束后 log');
}
// 调用方式:传入回调函数
dynamicFunc(callback);
2. 封装为Promise后的版本
javascript
// 封装为Promise的异步函数
function dynamicFuncAsync() {
return new Promise(resolve => {
setTimeout(() => {
console.log('1s 后显示');
resolve();
}, 1000);
});
}
const callback = () => {
console.log('在异步结束后 log');
}
// 调用方式:链式调用then
dynamicFuncAsync().then(callback);
二、AJAX请求的Promise封装实践
1. 传统AJAX回调写法
javascript
function ajax(url, success, fail) {
const client = new XMLHttpRequest();
client.open("GET", url);
client.onreadystatechange = () => {
if (this.readyState !== 4) return;
if (this.status === 200) {
success(this.response);
} else {
fail(new Error(this.statusText));
}
};
client.send();
}
// 调用方式:传入成功/失败回调
ajax('/ajax.json',
() => console.log('成功'),
() => console.log('失败')
);
2. Promise封装后的AJAX函数
javascript
function ajaxAsync(url) {
return new Promise((resolve, reject) => {
const client = new XMLHttpRequest();
client.open("GET", url);
client.onreadystatechange = () => {
if (this.readyState !== 4) return;
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
client.send();
});
}
// 调用方式:Promise链式处理
ajaxAsync('/ajax.json')
.then(response => console.log('成功:', response))
.catch(error => console.log('失败:', error.message));
三、核心封装原则总结
-
封装步骤关键点
- 在函数内部返回一个新的Promise实例
- 在原异步操作完成时,根据结果调用
resolve
或reject
- 异步操作的参数通过
resolve/reject
传递给后续.then
回调
-
优势对比
特性 传统回调函数 Promise封装 代码可读性 多层嵌套易形成回调地狱 链式调用更清晰 错误处理 需要层层传递错误回调 统一通过 .catch
捕获流程控制 难以实现并行/串行 支持 Promise.all/race
-
最佳实践建议
- 对所有异步API(如文件操作、网络请求)进行Promise封装
- 保持封装函数的参数简洁(如
ajaxAsync(url)
而非ajaxAsync(url, method, data)
) - 在
.catch
中处理全局错误,避免Promise链中断
四、高级封装技巧
-
处理多参数回调
javascript// 原函数(返回多个结果) function processData(data, success, fail) { // 异步处理data success(result1, result2); } // Promise封装 function processDataAsync(data) { return new Promise((resolve, reject) => { processData(data, (res1, res2) => resolve({ result1: res1, result2: res2 }), error => reject(error) ); }); } // 调用时解构参数 processDataAsync(data) .then(({ result1, result2 }) => { /* 处理多结果 */ })
-
封装Node.js风格的回调函数
javascript// Node.js传统回调:第一个参数为错误(error-first) const fs = require('fs'); // 封装fs.readFile function readFileAsync(path) { return new Promise((resolve, reject) => { fs.readFile(path, (error, data) => { if (error) reject(error); resolve(data); }); }); } // 调用方式 readFileAsync('/data.txt') .then(data => console.log('文件内容:', data)) .catch(error => console.error('读取失败:', error));
五、总结:Promise封装的核心价值
-
代码结构优化
将"回调地狱"转化为线性的链式调用,提升代码可维护性。
-
错误处理标准化
通过统一的
.catch
机制处理异步错误,避免传统回调中错误传递的遗漏。 -
异步流程增强
支持Promise组合操作(如
Promise.all
并行执行多个异步任务),简化复杂异步流程控制。
通过上述封装方式,任何异步操作都能转化为Promise接口,从而充分利用ES6异步编程的优势,让代码更简洁、更健壮。