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

拖拽文件夹上传:如何确保所有Promise完成后再执行后续代码?

解决拖拽上传文件夹时文件未加载完成就执行后续代码的问题

我通过拖拽字段上传文件夹中的所有文件,将文件夹拖放到dropField后会调用handleDrop()方法。原本期望所有文件加载完成并存入files变量后,再传入this.loadFiles()方法完成上传,但目前traverseDirectory中的Promise还未全部resolve,后续代码就已经执行了——日志“The FileArray:”显示files数组为空,之后Promise才逐个resolve。

当前代码如下:

retrieveFilefromFileEntry: async function (fileEntry, files) {
      return new Promise((resolve) => {
        fileEntry.file((file) => {
          resolve(file);
        });
      });
    },

handleDrop: function (ev) {
  const files = [];

  const items = ev.dataTransfer.items;
  for (let i = 0; i < items.length; i++) {
    const item = items[i].webkitGetAsEntry();
    if (item) {
      this.traverseDirectory(item, files);
    }
  }
  this.fileCount = files.length;
  console.log(`The FileArray: ${files}`);
  
  if (files.length > 0) {
    this.isUploadButtonVisible = true;  // 控制按钮显示的变量
    this.loadFiles(files);
  }
},

traverseDirectory: async function (item, files) {
  if (item.isFile) {
    await this.retrieveFilefromFileEntry(item, files).then((file) => {
      files.push(file);
    });
    console.log(`The Files are ${files}`);
  } else {
    const directoryReader = item.createReader();
    directoryReader.readEntries((entries) => {
      for (const entry of entries) {
        this.traverseDirectory(entry, files);
      }
    });
  }
},

解决方案

要确保所有文件加载完成后再执行后续代码,需要从异步流程控制入手,修改以下几点:

  1. 将handleDrop改为async函数,以便等待所有异步操作完成
  2. 把traverseDirectory中处理目录的回调式方法包装为Promise,确保递归时等待所有子条目处理完成
  3. 在handleDrop中收集所有traverseDirectory的Promise,用Promise.all等待全部完成后再执行后续逻辑

修改后的完整代码:

retrieveFilefromFileEntry: async function (fileEntry) {
  return new Promise((resolve) => {
    fileEntry.file((file) => {
      resolve(file);
    });
  });
},

// 新增:将readEntries包装为Promise,处理分批返回条目的情况
readAllEntries: async function (directoryReader) {
  const entries = [];
  let batch;
  do {
    batch = await new Promise((resolve) => {
      directoryReader.readEntries(resolve);
    });
    entries.push(...batch);
  } while (batch.length > 0);
  return entries;
},

handleDrop: async function (ev) {
  ev.preventDefault(); // 防止浏览器默认打开文件的行为
  const files = [];
  const items = ev.dataTransfer.items;
  const traversePromises = [];

  for (let i = 0; i < items.length; i++) {
    const item = items[i].webkitGetAsEntry();
    if (item) {
      // 收集所有遍历目录的Promise
      traversePromises.push(this.traverseDirectory(item, files));
    }
  }

  // 等待所有文件遍历完成
  await Promise.all(traversePromises);

  this.fileCount = files.length;
  console.log(`The FileArray: ${files}`);
  
  if (files.length > 0) {
    this.isUploadButtonVisible = true;
    this.loadFiles(files);
  }
},

traverseDirectory: async function (item, files) {
  if (item.isFile) {
    const file = await this.retrieveFilefromFileEntry(item);
    files.push(file);
    console.log(`The Files are ${files}`);
  } else {
    const directoryReader = item.createReader();
    const entries = await this.readAllEntries(directoryReader);
    // 等待所有子条目处理完成
    await Promise.all(entries.map(entry => this.traverseDirectory(entry, files)));
  }
},

关键修改说明

  • readAllEntries方法:解决directoryReader.readEntries可能分批返回条目的问题,循环调用直到获取所有目录条目
  • handleDrop改为async,用Promise.all等待所有遍历操作完成,再处理files数组
  • traverseDirectory中处理目录时,用Promise.all等待所有子条目的遍历Promise完成,确保递归流程同步

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 22:36:30