promise 包装回调函数的核心是将“有回调参数的函数”改造为“返回 promise 的函数”,以便支持 .then() 和 async/await;需先明确原函数回调签名,再用 promise 构造器封装,注意参数透传与上下文保持。

用 Promise 包装回调函数,核心是把“有回调参数的函数”改造成“返回 Promise 的函数”,让异步逻辑能用 .then() 和 async/await 串起来,避开层层嵌套。
明确回调函数的签名
先看清原函数怎么用:它是否接受 success 和 error 回调?还是只传一个回调(常见于 Node.js 风格的 (err, data) => {})?这是包装的前提。
- Node.js 风格(如
fs.readFile):回调第一个参数是错误,第二个是结果 - 浏览器 API 风格(如
setTimeout):通常只有成功回调,无显式错误参数 - 自定义 API:需按实际文档判断参数顺序和含义
用 Promise 构造器封装单个回调函数
最通用的方式是用 new Promise 包一层,把回调里的成功和失败分别对应到 resolve 和 reject:
function promisify(fn) {
return function(...args) {
return new Promise((resolve, reject) => {
fn(...args, (err, result) => {
if (err) reject(err);
else resolve(result);
});
});
};
}
例如包装 fs.readFile:
const readFile = promisify(fs.readFile);
readFile('data.txt', 'utf8')
.then(data => console.log(data))
.catch(err => console.error(err));
处理只带成功回调的函数(如 setTimeout)
这类函数没有错误路径,可直接 resolve,也可加超时控制或手动抛错:
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// 使用
delay(1000).then(() => console.log('1秒后执行'));
若想支持取消或错误注入,可扩展为:
function delay(ms, signal) {
return new Promise((resolve, reject) => {
if (signal && signal.aborted) {
reject(new DOMException('AbortError'));
return;
}
const timer = setTimeout(resolve, ms);
signal?.addEventListener('abort', () => {
clearTimeout(timer);
reject(new DOMException('AbortError'));
});
});
}
批量转换与现代替代方案
Node.js 从 v8 开始内置 util.promisify,可直接转换标准回调函数:
const { promisify } = require('util');
const readFile = promisify(fs.readFile);
浏览器中部分 API 已原生支持 Promise(如 fetch、FileReader.readAsText 返回 Promise),优先用原生版本,避免手动包装。
不复杂但容易忽略:包装时别漏掉参数透传,尤其是上下文(this)和剩余参数(...args),否则会丢失调用时的原始行为。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











