2015-12-01 2 views
3

Привет, я довольно новичок в Javascript, Nodejs и его асинхронном мире, и я пытаюсь получить размер списка папок (например, du command) асинхронным способом. Что-то вроде:Nodejs асинхронный рекурсивный размер папки

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

То, что я ожидал, чтобы получить результат от обратного вызова в качестве asyinch способом так, когда du покрытие для folderN обратного вызова распечатывает результат для folderN.

Я попытался с помощью этого кода из 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 

Проблема я получил с этим кодом, который использует CLOSURES является то, что если второй вызов du начинается, когда первый вызов все еще выполняется, все перепутано, потому что Closure повторно использует текущие значения для total, file_counter и async_running.

+0

Спасибо за ваши ответы, используя обещание, но первым я бы как понять основные понятия асинхронных nodejs (используя обратные вызовы), а затем использовать библиотеку andvaced, такую ​​как Promise или Asynch. – Ettore

ответ

2

Я считаю, обратные вызовы немного громоздким, поэтому использование Promise это еще асинхронным, надеюсь, комментарии прояснить вещи ...

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)); 
0

Сначала я думаю, что вы должны научиться, прежде чем, как иметь дело с несколькими асинхронными операциями вы должны искать для 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); 
 
      }); 
 
     }) 
 
    ) 
 
    }); 
 
}

С помощью этого кода вы можете рекурсивно просмотра для каждого подпроекта каталога

Смежные вопросы