【问题标题】:How to wait for the response of all async fs.rename without blocking the process?如何在不阻塞进程的情况下等待所有 async fs.rename 的响应?
【发布时间】:2019-10-28 01:56:49
【问题描述】:

我构建了一个 Angular/Node 应用程序,用于重命名网络文件夹中的文件。它重命名的文件数量在 300 到 500 之间。我使用 await 以便在重命名完成时收到通知。每次运行需要 8-10 分钟,因为我使用的是 await,所以不能同时重命名。

我需要传递重命名文件的数量,并且我需要向用户显示重命名已经完成。如果我不使用 async/await,我的 Angular 前端怎么知道重命名完成了?

我的完整代码在这里:https://github.com/ericute/renamer

这就是我遇到问题的地方:

    await walk(folderPath, function(err, results) {

        if (err) throw err;            

        results.forEach(file => {

            if (fs.lstatSync(file).isFile) {
                fileCounter++;
            }

            let fileBasename = path.basename(file);
            let filePath = path.dirname(file);

            if (!filesForRenaming[path.basename(file)]) {
                //In a javascript forEach loop,
                //return is the equivalent of continue
                //https://stackoverflow.com/questions/31399411/go-to-next-iteration-in-javascript-foreach-loop
                return;
            }

            let description = filesForRenaming[path.basename(file)].description;

            // Process instances where the absolute file name exceeds 255 characters.
            let tempNewName = path.resolve(filePath, description + "_" + fileBasename);            
            let tempNewNameLength = tempNewName.length;
            let newName = '';            

            if (tempNewNameLength > 255) {
                let excess = 254 - tempNewNameLength;
                if (description.length > Math.abs(excess)) {
                    description = description.substring(0, (description.length - Math.abs(excess)));
                }
                newName = path.resolve(filePath, description + "_" + fileBasename);                
            } else {
                newName = tempNewName;
            }

            renamedFiles++;
            // Actual File Renaming
            fs.renameSync(file, newName, (err) => {
                if (err) { 
                    errList.push(err);
                }
                renamedFiles++;
            });

        });

        if (Object.keys(errList).length > 0) {
            res.send({"status":"error", "errors": errList});
        } else {
            res.send({
                "status":"success",
                "filesFoundInDocData": Object.keys(filesForRenaming).length,
                "filesFound": fileCounter,
                "renamedFiles": renamedFiles,
                "startDate": startDate
            });
        }
    });

【问题讨论】:

  • 您的代码应该会抛出错误,因为您不会等待这样的函数定义。此外,没有理由使用它,因为您使用的是 fs 命令的 *Sync 版本,它们不是异步的......
  • 嗨@HereticMonkey,感谢您检查我的问题。如果我不使用同步,如何收到重命名完成的通知?这就是我需要的:(1)进行重命名(2)在不阻塞进程的情况下得到通知。
  • 非同步版本允许您传递回调。或者你可以使用util.promisfy 来做出承诺,这样你就可以使用 async/await。有许多关于在 Node 中异步执行操作的教程和问题。

标签: node.js angular fs


【解决方案1】:

如果您使用任何同步方法,基本上就是在阻塞事件循环。您必须更改代码的整个结构并开始在任何地方使用 Promise。您应该能够以角度创建另一个服务,以检查重命名过程是否使用 timeInterval 和 GET 请求(最简单的方法)完成。例如,您可以设置角度以从“/isRenameCompleted”获取数据,并在结果为真或其他情况时提醒用户。要获得实时结果,您必须切换到 socket-io。 1 个客户端的快速解决方案(因为您需要为每个请求存储唯一的 ID 并相应地获取承诺)可能是这样的:

1:在代码之上创建两个全局变量

var filesStatus="waiting"
var pendingFiles=[]

2:在重命名逻辑路由中,使用 for 循环将 每个文件 推送到 promise 数组,并开始异步等待重命名过程完成

pendingFiles.push(fsPromises.rename(oldName,newName))
Promise.all(pendingFiles)
  .then(values => { 
    filesStatus = "done"
  })
  .catch(error => { 
    filesStatus = "error"
  });
filesStatus="pending"

3:现在添加一个新路由/isRenameCompleted,它将具有如下报告逻辑

router.get('/isRenameCompleted', (req, res, next) => {
 if (filesStatus==="pending"){
    res.end("please wait")
 } else if (filesStatus==="done"){
    res.end("done! your files renamed")   
 }
}

【讨论】:

  • 我一直在根据您的建议重写我的代码。完成后,我将更新我的存储库以反映我的更改。非常感谢您的指导!
猜你喜欢
  • 2015-09-18
  • 1970-01-01
  • 1970-01-01
  • 2011-06-17
  • 1970-01-01
  • 2020-07-24
  • 1970-01-01
  • 2015-12-07
  • 2020-12-01
相关资源
最近更新 更多