如何在 Javascript 中等待递归 Promise

Ser*_*gio 2 javascript recursion promise async-await

我在 javascript 中编写了一个递归 Promise,它似乎工作正常,但我想使用 setTimeout() 对其进行测试,以确保在继续执行之前我正在正确等待。这是我的代码的要点:

try{
  await renameFiles(); // <-- await here
  console.log("do other stuff");
}
catch(){
}

const renameFiles = (path) => {
  return new Promise(resolve => {
    console.log("Renaming files...");

    fs.readdirSync(path).forEach(file) => {
      // if file is a directory ...
      let newPath = path.join(path, file);
      resolve( renameFiles(newPath) ); // <- recursion here!
      // else rename file ...
    }
    resolve();
  })
Run Code Online (Sandbox Code Playgroud)

我已经用 setTimeout() 对其进行了测试,如下所示:

const renameFiles = () => {
  return new Promise(resolve => {
    setTimeout(() => {
    // all previous code goes here
    },2000)
  }
}
Run Code Online (Sandbox Code Playgroud)

输出是:

"Renaming files..."
"Renaming files..."
// bunch of renaming files...
"do other stuff"
"Renaming files..."
"Renaming files..."
Run Code Online (Sandbox Code Playgroud)

所以看起来它正在等待一段时间,但随后它会在某个时刻继续执行。

我也怀疑我测试错了。知道问题可能出在哪里吗?

uda*_*mik 5

正如已经提到的 - 多次解析调用没有意义。但这并不是代码中唯一的问题。当对第一个子目录开始递归调用时,根调用得到解决。此代码将按层次顺序处理目录

重命名.js

const fs = require('fs');
const path = require('path');

const inputPath = path.resolve(process.argv[2]);
const newName = 'bar.txt';

async function renameFiles(filePath) {
    for (const file of fs.readdirSync(filePath)) {
        const newPath = path.join(filePath, file);
        const descriptor = fs.lstatSync(newPath);
        if (descriptor.isDirectory()) {
            await renameFiles(newPath)
        } else if (descriptor.isFile()) {
            await renameFile(file);
        }
    }
}

async function renameFile(file) {
    console.log(`Renaming ${file} to ${newName}`)
    return new Promise(resolve => {
       setTimeout(() => {
           console.log(`Renamed ${file} to ${newName}`)
           resolve();
       }, 300)
    });
}

async function main() {
    console.log(`Renaming all files in ${inputPath} to ${newName}`);
    await renameFiles(inputPath);
    console.log('Finished');
}

main();
Run Code Online (Sandbox Code Playgroud)

你可以像这样运行它

node rename.js relativeFolderName
Run Code Online (Sandbox Code Playgroud)

或者如果顺序不重要,那么您可以使用@Tiago Coelho 提到的mapandPromise.all

const renameFiles = async path => {
    const renamePromises = fs.readdirSync(path).map(file => {
      if (isDirectory(file)) {
          const newPath = path.join(path, file);
          return renameFiles(newPath)
      } else {
          return renamefile(file);
      }  
    });
    await Promise.all(renamePromises);
}
Run Code Online (Sandbox Code Playgroud)