如何在不阻止进程的情况下等待所有异步fs.rename的响应?

时间:2019-06-13 12:57:08

标签: node.js angular fs

我构建了一个Angular / Node应用程序,用于重命名网络文件夹中的文件。它重命名的文件数量在300到500之间。我使用await,以便在重命名完成时得到通知。每次运行需要8到10分钟,并且由于我正在使用await而无法同时重命名。

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

我的完整代码在这里: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
            });
        }
    });

1 个答案:

答案 0 :(得分:0)

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

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")   
 }
}