原生 Promise 不支持进度通知,但可通过自定义构造函数(如 createProgressPromise)封装实现:执行器接收 resolve、reject 和 progress 三参数,progress 调用外部 onProgress 回调传递进度数据,返回标准 Promise;也可结合事件发射器或使用 axios、RxJS 等支持进度的第三方库,注意进度仅为副作用,不参与 Promise 状态机。

原生 Promise 不支持进度通知,但可以通过自定义构造函数或封装方式实现带进度回调的 Promise 任务。核心思路是:在 Promise 执行过程中主动调用外部传入的 onProgress 回调,并将当前进度(如百分比、步骤描述等)作为参数传递出去。
手动封装支持进度的 Promise 构造函数
你可以创建一个类似 ProgressPromise 的工厂函数,接受执行器(executor)和进度回调:
- 执行器函数接收
resolve、reject和progress三个参数(第三个是自定义的进度通知函数) -
progress函数内部触发用户传入的onProgress回调 - 返回一个标准 Promise,保持与原生 Promise 兼容
示例代码:
function createProgressPromise(executor, onProgress) {
return new Promise((resolve, reject) => {
const progress = (value) => {
if (typeof onProgress === 'function') {
onProgress(value);
}
};
executor(resolve, reject, progress);
});
}
// 使用示例:模拟上传过程
createProgressPromise((resolve, reject, progress) => {
let i = 0;
const timer = setInterval(() => {
i += 10;
progress({ loaded: i, total: 100, percent: i });
if (i >= 100) {
clearInterval(timer);
resolve('上传完成');
}
}, 200);
}, (p) => console.log('进度:', p));
用 async/await + 进度事件模拟更自然的流程
如果你希望在 async 函数中使用进度,可以配合事件发射器或状态对象管理进度,再用 Promise 包装异步操作:
立即学习“Java免费学习笔记(深入)”;
- 定义一个带
onProgress监听能力的对象(如UploadTask) - 在关键节点调用
this.emit('progress', data)或直接执行回调 - Promise 的 resolve/reject 仍由主逻辑控制,不影响进度通知的独立性
这样写能让业务逻辑更清晰,也方便复用和测试。
借助第三方库简化开发(如 axios、rxjs)
很多成熟库已内置进度支持:
-
axios:通过
onUploadProgress配置项监听上传进度(基于 XMLHttpRequest 的upload.onprogress) -
RxJS:用
Subject或fromEvent发送进度流,再用toPromise()或lastValueFrom转为 Promise - 不推荐强行给 Promise 增加“多状态”语义,应区分「最终结果」和「中间反馈」两种关注点
注意事项与常见误区
实现时需注意几个关键点:
- Promise 一旦 fulfilled 或 rejected,就不能再改变状态;进度只是额外通知,不参与 Promise 状态机
- 避免在
progress回调中做耗时操作,否则可能阻塞主线程或影响性能 - 不要试图修改原生 Promise.prototype —— 违反规范且不可靠
- 如果需要取消任务,应单独设计 cancel 方法或使用 AbortController(Promise 本身不支持取消)
本质上,进度通知是副作用行为,应与 Promise 的终态解耦处理。只要明确职责边界,就能写出既符合直觉又稳定可靠的进度感知任务。


















