JavaScript中Async/await批量文件操作执行顺序不符合预期问题排查
问题分析
- 第一个问题:
copy和rename方法没有正确返回异步操作的Promise
你虽然给这两个函数加了async关键字,但内部调用的是回调风格的fs.copyFile和fs.rename,这两个方法执行后会立刻返回,不会等待回调执行。async函数如果没有返回自定义Promise、也没有await异步操作的话,会立刻返回状态为resolved的Promise,所以你写的await copy(e)和await rename(e,index)根本不会等待文件操作完成,就会直接执行后面的日志打印逻辑。 - 第二个问题:
forEach不支持异步等待Array.prototype.forEach是同步遍历方法,当你传入async回调函数时,它只会并发触发所有回调,不会等待任何一个回调的异步逻辑执行完成。所以你所有的文件复制、重命名逻辑还在后台执行的时候,外层的console.log(total)就已经先执行了,此时total还没被赋值,自然输出0。
修复方案
- 改用fs的promise版本API,让
copy和rename正确返回等待文件操作完成的Promise - 把forEach遍历替换为
for...of循环,保证执行顺序符合你预期的逐次执行逻辑,所有文件操作都执行完成后再打印total值。
修正后的完整代码
const fs = require("fs"); const fsPromise = fs.promises; // 引入promise版本的fs操作接口 const path = "C:\\Users\\shepard\\Desktop\\Head"; const newPath = "C:\\Users\\shepard\\Desktop\\NewHead"; let files = fs.readdirSync(path); const rarityList = [{name: "a", value: 3},{name: "b", value: 2}]; let total = 0; const copy = async (_e) => { await fsPromise.copyFile(path + "\\" + _e, newPath + "\\" + _e); }; const rename = async (_e, _index) => { let t = _e.replace(".png", "#" + rarityList[_index].value + ".png") await fsPromise.rename(newPath + "\\" + _e, newPath + "\\" + t); }; // 用自执行async函数包裹所有异步逻辑,实现顶层等待 (async () => { // 用for...of替代forEach,保证顺序执行 for (const e of files) { await copy(e); console.log("Copying is done!"); for (const [index, element] of rarityList.entries()) { if (element.name == e.slice(0,-4)) { await rename(e,index); console.log("Renaming is done! for " + e + " with the rarity weight of " + rarityList[index].value); total += rarityList[index].value; }; } } // 所有操作执行完成后再打印总和 console.log(total); })().catch(err => console.log(err));
内容的提问来源于stack exchange,提问作者Commander Shepard
相关产品推荐
相关产品推荐

