【问题标题】:Nodejs asynchronous recursive folder sizeNodejs异步递归文件夹大小
【发布时间】:2016-03-05 03:59:59
【问题描述】:

您好,我对 Javascript、Nodejs 及其异步世界还很陌生,我正在尝试以异步方式获取文件夹列表的大小(如 du 命令)。比如:

du = function(directory, callback){
    ...
}

displaySum = function(err, result) {
    if(!err) {console.log(result);}
}

var folders = ['/folder1', '/folder2', '/folder3'];
for (var i = 0; i < folders.length; i++) {
   du(folders[i], displaySum);
}

我期望以异步方式从回调中获取结果,因此当 du 完成文件夹 N 时,回调会打印出文件夹 N 的结果。

我尝试使用来自 here 的这段代码,它使用了柯里化和闭包:

//Pseudocode
duAsync4 = (dir,cb) ->
    total = 0
    file_counter = 1 #starts at one because of the initial directory
    async_running = 0

    again = (current_dir) ->
       fs.lstat current_dir, (err, stat) ->
           if err then file_counter--; return
           if stat.isFile()
               file_counter--
               total += stat.size
           else if stat.isDirectory()
               file_counter--
               async_running++
               fs.readdir current_dir, (err,files) ->
                   async_running--
                   if err then return #console.log err.message
                   file_counter += files.length
                   for file in files
                       again path.join(current_dir, file)
           else
               file_counter--
           if file_counter is 0 and async_running is 0
               cb(null, total)

again dir

我在使用 闭包 的代码中遇到的问题是,如果在第一个调用仍在进行时对 du 的第二次调用开始,那么一切都会因为闭包重复使用而变得一团糟total、file_counter 和 async_running 的当前值。

【问题讨论】:

  • 感谢您使用 Promise 的回答,但首先我想了解异步 nodejs(使用回调)的基本概念,然后使用诸如 Promise 或 Asynch 之类的高级库。

标签: javascript node.js asynchronous closures currying


【解决方案1】:

我觉得回调有点麻烦,所以使用Promise它仍然是异步的,希望cmets澄清事情......

var fs = require('fs')
  , path = require('path');

function getSize(dirPath){      
  return getStat(dirPath).then(function(stat){  
    if(stat.isFile()){  // if file return size directly
      return stat.size;
    }else{
      return getFiles(dirPath).then(function(files){    // getting list of inner files
        var promises = files.map(function(file){
          return path.join(dirPath, file);  
        }).map(getSize);    // recursively getting size of each file
        return Promise.all(promises);   
      }).then(function(childElementSizes){  // success callback once all the promise are fullfiled i. e size is collected 
          var dirSize = 0;
          childElementSizes.forEach(function(size){ // iterate through array and sum things
              dirSize+=size;
          });
          return dirSize;
      });
    }    
  });
}

// promisified get stats method
function getStat(filePath){
  return new Promise(function(resolve, reject){
    fs.lstat(filePath, function(err, stat){
      if(err) return reject(err);
      resolve(stat);
    });
  });
}

// promisified get files method
function getFiles(dir){
  return new Promise(function(resolve, reject){
    fs.readdir(dir, function(err, stat){
      if(err) return reject(err);
      resolve(stat);
    });
  });  
}

// example usage
getSize('example dir').then(function(size){
    console.log('dir size: ', size);
}).catch(console.error.bind(console));

【讨论】:

    【解决方案2】:

    首先我认为你必须学习如何处理多个异步操作之前你必须寻找 Promise 或 async js 之类的库。

    接下来你可以试试这样的:

    var fs = require('mz/fs');
    
    var myDir = './';
    
    readdir(myDir)
    function readdir(dir) {
      fs.readdir(dir)
        //mz fs transform all fs functions to promises
        .then(function(files) {
    
        //wait each promises
        return Promise.all(
          files.map(function(file) {
    
            return fs.lstat(file)
              .then(function(stats) {
    
                //the function is recursive
                if (stats.isDirectory())
                  return readdir(file);
              });
          })
        )
      });
    }

    使用此代码,您可以递归查找每个子目录

    【讨论】:

      猜你喜欢
      • 2018-12-17
      • 2012-05-29
      • 2015-10-30
      • 2022-07-29
      • 2014-05-21
      • 2013-07-11
      • 1970-01-01
      • 2015-03-14
      • 2012-06-16
      相关资源
      最近更新 更多