You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JavaScript中用Promise实现上传状态更新?

问题分析与解决方案

咱们先搞定你当下遇到的回调参数异常问题,再聊聊Promise有没有进度监听的替代方案:

一、为什么回调里的progress是undefined?

看你代码里调用回调的这行:

callbackProgress.call(percentage, id)

这里踩了call方法的使用坑:call的第一个参数是指定回调执行时的this上下文,从第二个参数开始才是传给回调的实际参数。你把percentage放在了第一个位置,导致回调里的progress拿到的是this(非严格模式下会被转成包装对象,严格模式直接是undefined),而id才是第一个真实传入的参数——这就是为啥只有id正常,progress是undefined的原因!

修复方法很简单,二选一就行:

  1. 如果你不需要指定回调的this,直接调用就行:
callbackProgress(percentage, id)
  1. 如果确实要指定this,把上下文(比如null或者你需要的对象)放在第一个参数位置:
callbackProgress.call(null, percentage, id)

二、Promise有没有onProgressChange这类方法?

很遗憾,原生Promise本身没有内置的进度监听方法——因为Promise的设计初衷是代表「单一异步结果」(要么成功resolve,要么失败reject),它不支持多次状态更新。不过咱们有几种替代方案实现进度上报:

1. 继续用回调(最省心的方案)

修复刚才的调用问题后,这个方案就能正常工作,也是日常开发中最常用的进度上报方式,不需要额外折腾。

2. 封装自定义的带进度Promise类

如果你想脱离回调的写法,可以自己封装一个扩展原生Promise的类,给它加进度监听能力:

class ProgressPromise extends Promise {
  constructor(executor) {
    super((resolve, reject) => {
      // 给executor多传一个更新进度的方法
      return executor(resolve, reject, (progress, id) => {
        if (this.onProgressHandler) {
          this.onProgressHandler(progress, id);
        }
      });
    });
  }

  // 定义进度监听方法
  onProgress(callback) {
    this.onProgressHandler = callback;
    return this;
  }
}

// 改造你的uploadImages函数
export const uploadImages = (images) => {
  return new ProgressPromise((resolve, reject, updateProgress) => {
    // 原来的上传逻辑里,需要上报进度时调用updateProgress(percentage, id)
    const myUploadProgress = (thumbId) => (progress) => {
      let id = thumbId;
      let percentage = Math.floor((progress.loaded * 100) / progress.total);
      updateProgress(percentage, id); // 用这个方法更新进度
    };

    // ...剩下的上传逻辑和之前一样
    var originals = []
    var thumbnails = []
    let totalNrOfImages = images.length
    var uploadImageCounter = 0
    var i;
    for (i = 0; i < images.length; i++) {
      var thumbId = i
      var config = { onUploadProgress: myUploadProgress(thumbId) };
      const formData = new FormData()
      formData.append('img', images[i])
      uploadImage2(formData, config).then(resp => {
        originals.push(resp.oriUrl)
        thumbnails.push(resp.thumbUrl)
        uploadImageCounter=uploadImageCounter+1
        if(images.length == uploadImageCounter){
          resolve({orig:originals, thumbs:thumbnails});
        }
      })
    }
  });
};

// 调用时就可以链式监听进度了
uploadImages(fileList)
  .onProgress((progress, id) => {
    console.log(`SCENE1 | uploadImages() | id: ${id}, progress: ${progress}%`);
  })
  .then(response => {
    console.log("SCENE1 | uploadImages() | done, response: ", response);
  })
  .catch(error => {
    console.log("SCENE1 | uploadImages() | error!");
  });

3. 用事件发射器传递进度

如果你的项目里有用事件相关的能力(浏览器的EventTarget或者Node.js的EventEmitter),也可以用事件来传递进度:

export const uploadImages = (images) => {
  const progressEmitter = new EventTarget();
  const promise = new Promise((resolve, reject) => {
    const myUploadProgress = (thumbId) => (progress) => {
      let id = thumbId;
      let percentage = Math.floor((progress.loaded * 100) / progress.total);
      // 触发进度事件
      progressEmitter.dispatchEvent(new CustomEvent('upload-progress', {
        detail: { progress, id }
      }));
    };

    // ...剩下的上传逻辑和之前一样
    var originals = []
    var thumbnails = []
    let totalNrOfImages = images.length
    var uploadImageCounter = 0
    var i;
    for (i = 0; i < images.length; i++) {
      var thumbId = i
      var config = { onUploadProgress: myUploadProgress(thumbId) };
      const formData = new FormData()
      formData.append('img', images[i])
      uploadImage2(formData, config).then(resp => {
        originals.push(resp.oriUrl)
        thumbnails.push(resp.thumbUrl)
        uploadImageCounter=uploadImageCounter+1
        if(images.length == uploadImageCounter){
          resolve({orig:originals, thumbs:thumbnails});
        }
      })
    }
  });
  return { promise, progressEmitter };
};

// 调用方式
const { promise, progressEmitter } = uploadImages(fileList);
progressEmitter.addEventListener('upload-progress', (e) => {
  const { progress, id } = e.detail;
  console.log(`SCENE1 | uploadImages() | id: ${id}, progress: ${progress}%`);
});
promise.then(response => {
  console.log("SCENE1 | uploadImages() | done, response: ", response);
}).catch(error => {
  console.log("SCENE1 | uploadImages() | error!");
});

总结

先把回调的调用方式改对,这是解决当前progress为undefined的核心;如果想优化写法,根据自己的项目场景选自定义Promise类或者事件的方式就行。

内容的提问来源于stack exchange,提问作者KasparTr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:37:07