【问题标题】:Unlinking a folder of files by async is super slow通过异步取消链接文件的文件夹非常慢
【发布时间】:2017-07-21 01:24:12
【问题描述】:

我正在尝试通过fs 调用清空文件夹的 http 请求。我们假设没有子文件夹。因为forEach不是异步的,所以我选择使用asynceach而不是forEach。代码如下:

后端:

router.post('/emptyDir', function (req, res, next) {
    console.log("router.post /emptyDir");
    var dir = req.body.dir;
    var fs = require('fs');
    var async = require('async');
    fs.readdir(dir, function (err, files) {
        if (err) return console.log(err);
        console.log(JSON.stringify(files));
        async.each(files, function (file) {
            fs.unlink(dir + file, function (err) {
                if (err) return console.log(err);
                console.log(dir + file + " is removed");
            })
        }, function (err) {
            if (err) return console.log('A file failed to be removed');
            console.log('All files have been successfully removed');
            return res.json(dir);
        })
    });
});

前端:

this.rewriteAllFiles = function (files) {
    return $http.post('/emptyDir', { dir: prefix + idP + "/" })
        .then(function (res) {
            console.log("emptyDir finished");
            ...

我使用包含 2 个文件的文件夹运行测试。它首先在浏览器日志中不显示任何内容,然后在后端显示以下日志:

router.post /emptyDir
["index.html","script.js"]
public/tmp/BGMTbU0RbeHdLAMjAAAD/index.html is removed
public/tmp/BGMTbU0RbeHdLAMjAAAD/script.js is removed

2分钟后,浏览器日志中显示emptyDir finished,后台再次显示router.post /emptyDir

router.post /emptyDir
[]
All files have been successfully removed

我不明白为什么/emptyDir 被调用了两次,为什么需要这么长时间......

那么有人知道哪里错了吗?

编辑 1: 我意识到使用 Array.forEach 至少对我的测试有效。但我不确定它是否逻辑上正确。下面的函数能否返回files.forEach的块完成之前?

router.post('/writeFiles', function (req, res, next) {
    console.log("router.post writeFiles");
    var dir = req.body.dir, files = req.body.files;
    var fs = require('fs');
    files.forEach(function (file) {
        fs.writeFile(dir + file.name, file.body, function (err) {
            if (err) return console.log(err);
            console.log(dir + file.name + " is written");
        })
    });
    console.log("All files have been successfully written");
    return res.json(dir);
})

【问题讨论】:

    标签: javascript node.js asynchronous fs async.js


    【解决方案1】:

    我意识到,与the doc of async 相比,我忘记了async.each(files, function(file, callback) ...) 中的callback。以下代码有效:

    router.post('/emptyDir', function (req, res, next) {
        console.log("router.post /emptyDir");
        var dir = req.body.dir;
        var fs = require('fs');
        var async = require('async');
        fs.readdir(dir, function (err, files) {
            console.log(JSON.stringify(files));
            async.each(files, function (file, callback) {
                fs.unlink(dir + file, function (err) {
                    if (err) {
                        console.log(err);
                        callback(err)
                    } else {
                        console.log(dir + file + " is removed");
                        callback();
                    }
                })
            }, function (err) {
                if (err) return console.log('A file failed to be removed');
                console.log('All files have been successfully removed');
                return res.json(dir);
            })
        });
    });
    

    【讨论】:

      【解决方案2】:

      Unlink 是异步的,因此您的整个 foreach 循环与您的其余代码“同时”运行,对于 readdir 和节点中非“同步”的几乎每个函数都是相同的。

      我认为您可以考虑使用 Promises。您可以为您取消链接的每个文件创建一个 Promises 数组。然后,您将使用 Promise.all() 等待所有 Promise 的完成(或失败)。

      类似的东西(它需要一些“重组”,但就是这样):

      router.post('/emptyDir', function (req, res, next) {
          console.log("router.post /emptyDir");
          var dir = req.body.dir;
          var fs = require('fs');
          fs.readdir(dir, function (err, files) {
              if (err) return console.log(err);
              console.log(JSON.stringify(files));
              var unlinkQueue = files.map(function(file) {
                  return new Promise(function(resolve, reject) {
                      fs.unlink(dir + file, function (err) {
                          if (err) return reject(err);
                          console.log(dir + file + " is removed");
                          resolve(file);
                      });
                  });
              });
              Promise.all(unlinkQueue)
                  .then(function(files) {
                      console.log("All files have been successfully removed");
                      res.json(dir);
                  })
                  .catch(function(err) {
                      /* error */
                  });
          });
      }); 
      

      【讨论】:

        猜你喜欢
        • 2012-06-05
        • 1970-01-01
        • 2014-07-23
        • 2021-10-12
        • 1970-01-01
        • 1970-01-01
        • 2016-03-02
        • 2019-04-30
        • 1970-01-01
        相关资源
        最近更新 更多