拖拽文件夹上传:如何确保所有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); } }); } },
解决方案
要确保所有文件加载完成后再执行后续代码,需要从异步流程控制入手,修改以下几点:
- 将
handleDrop改为async函数,以便等待所有异步操作完成 - 把
traverseDirectory中处理目录的回调式方法包装为Promise,确保递归时等待所有子条目处理完成 - 在
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
相关产品推荐
相关产品推荐

