如何让函数等待jszip.loadAsync()执行并返回正确结果?
问题分析:async/await未生效导致Backup函数提前返回Pending Promise
问题描述
我是JavaScript及async/await的新手,尝试编写一个Backup函数读取zip压缩包,返回非空文件数、总文件数和文件总大小。但函数返回pending promise,且在Backup函数内的console.log输出前就打印了该promise,await未按预期生效。使用Node.js v18.12.1。
原Backup函数代码
const jszip = require('jszip') const fs = require('fs') async function Backup(path) { let files = 0 let notEmpties = 0 let size = 0 fs.readFile(path, async (err, data) => { if (err) console.log(err) await jszip.loadAsync(data).then((zip) => { zip.forEach(async (path, file) => { files++ await file.async('arraybuffer').then((data) => { if (data.byteLength > 0) { console.log(file.name, data.byteLength) notEmpties++ size += data.byteLength } }) }) }) }) return [notEmpties, files, size] }
原执行代码
async function start(){ return await Backup('C:\\Users\\Szymon\\Desktop\\(DOKUMENTY)20221027fbs083114601.zip') } //start try { console.log(start()); } catch (error) { console.log(error); }
核心问题点
- 异步回调导致函数提前返回:Backup函数中使用了
fs.readFile的回调写法,这个回调是异步执行的,但Backup函数会直接跳过回调逻辑,提前执行return语句,此时统计变量还是初始值0,且返回的Promise会提前resolve,而实际的zip解析逻辑还在后台运行。 - zip.forEach不支持异步等待:
zip.forEach不会等待传入的async回调执行完成,会一次性遍历所有zip条目,导致后续的await file.async(...)无法同步统计数据,异步流程完全失控。 - async/await与.then()混用导致逻辑混乱:代码中同时使用
await和.then()嵌套,破坏了async/await的线性异步流程,更容易出现时序问题。 - 执行代码未正确处理Promise:
console.log(start());直接打印了start函数返回的Promise对象,而不是等待Promise resolve后获取结果,所以会看到pending状态的Promise。
修正后的代码
改造后的Backup函数
使用Promise版本的文件读取API,并用Promise.all等待所有文件处理完成:
const jszip = require('jszip') const fs = require('fs').promises; // 使用Promise化的fs模块 async function Backup(path) { let files = 0 let notEmpties = 0 let size = 0 try { // 用await读取文件,替代回调写法 const data = await fs.readFile(path); // 等待zip包加载完成 const zip = await jszip.loadAsync(data); // 收集所有文件的异步处理任务 const fileTasks = []; zip.forEach((_, file) => { files++; // 将每个文件的处理逻辑包装为异步函数,加入任务数组 fileTasks.push(async () => { const fileData = await file.async('arraybuffer'); if (fileData.byteLength > 0) { console.log(file.name, fileData.byteLength); notEmpties++; size += fileData.byteLength; } }); }); // 等待所有文件处理任务完成 await Promise.all(fileTasks.map(task => task())); return [notEmpties, files, size]; } catch (err) { console.error('处理zip包时出错:', err); throw err; // 抛出错误让调用者捕获处理 } }
修正后的执行代码
正确等待Promise resolve后输出结果:
async function start(){ try { const result = await Backup('C:\\Users\\Szymon\\Desktop\\(DOKUMENTY)20221027fbs083114601.zip'); console.log('统计结果:', result); return result; } catch (error) { console.error('启动备份任务出错:', error); } } // 执行异步函数 start();
内容的提问来源于stack exchange,提问作者szymonITC
相关产品推荐
相关产品推荐

