用 Promise 封装回调的核心是将成功/失败回调转为 resolve/reject 调用并返回新 Promise;需区分 Node.js 错误优先模式(err, data)与无错误参数模式,注意只调用一次 resolve/reject、显式 reject 错误、必须返回 Promise。

用 Promise 封装传统回调函数,核心是把“成功回调”和“失败回调”转为 resolve 和 reject 的调用,并返回一个新 Promise 实例。
基本封装模式:适配 Node.js 风格回调(err, data)
大多数老式 API(如 Node.js 内置模块、部分第三方库)采用 callback(err, result) 形式。封装时需判断第一个参数是否为错误:
- 若
err存在,调用reject(err) - 若
err为null或undefined,调用resolve(result)
示例:封装 fs.readFile
function readFilePromise(path, encoding = 'utf8') {
return new Promise((resolve, reject) => {
fs.readFile(path, encoding, (err, data) => {
if (err) reject(err);
else resolve(data);
});
});
}
// 使用
readFilePromise('./data.txt')
.then(data => console.log(data))
.catch(err => console.error(err));
处理无标准错误优先的回调(仅 success 回调)
有些接口只传一个成功回调(如某些浏览器 API、事件触发类方法),没有显式错误参数。此时可:
立即学习“Java免费学习笔记(深入)”;
- 监听其内部可能抛出的异常,用
try/catch包裹调用逻辑 - 手动监听错误事件(如
onerror、reject触发时机需明确) - 设置超时兜底,避免 Promise 永远不兑现
示例:封装 setTimeout(无错误,但可加超时控制)
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
// 封装带超时的异步操作(如 fetch 超时)
function timeout(promise, ms) {
return Promise.race([
promise,
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), ms)
),
]);
}
复用封装:通用 promisify 工具函数
Node.js 从 v8.0+ 提供了 util.promisify,可自动将符合 Node.js 回调规范的函数转为 Promise 版本:
const { promisify } = require('util');const readFile = promisify(fs.readFile);
const stat = promisify(fs.stat);
readFile('./config.json').then(...);
自定义简易 promisify(适用于简单场景):
return function(...args) {
return new Promise((resolve, reject) => {
fn(...args, (err, result) => {
if (err) reject(err);
else resolve(result);
});
});
};
}
注意事项与常见陷阱
- 不要重复 resolve/reject:确保回调中只调用一次,避免多次执行造成未定义行为
-
错误必须 reject,不能 throw:在 Promise 构造器回调中
throw会直接被转为reject,但显式写reject()更清晰可控 - 避免忘记 return Promise:封装函数必须返回 Promise,否则无法链式调用
-
兼容性考虑:旧环境需 Promise polyfill(如
es6-promise)


















