2014-05-14 23 views
0

我正在研究一個使用文件樹的Web應用程序。前端JavaScript對我的Node.js服務器執行ajax請求,該服務器調用我的browse2導出函數。這個函數然後負責爲我的函數getFolderContents()提供正確的路徑,遞歸地構建文件系統層次結構對象結構。異步執行遞歸數據樹構造?

我的問題是,我目前正在同步做事。在研究了Node.js的內部工作之後,似乎我應該不惜一切代價避免同步操作。因此,我想將我的代碼異步工作。但是,我無法實現它,所有解決方案都很複雜。

我曾嘗試使用「異步」包管理流程。我沒有想到這一點。我嘗試實現我自己的計數器/循環/回調系統,以確定進程何時完成執行。最終,我想我無法將自己的想法包裝在異步執行流程中。

我想問兩個問題: 1.在這種情況下,同步而不是異步執行此請求會有害嗎? 2.如果對第一個問題是,我應該如何將此代碼轉換爲異步?

注意:當我嘗試異步執行某些操作時,我使用了每個同步函數的異步對象。

下面是我的同步(工作)代碼:

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

exports.browse2 = function(request, response) { 
    var tree = getFolderContents('C:\\Users\\AccountName\\folder1\\folder2\\folder3\\test\\'); 

    response.send(tree); 
}; 


function getFolderContents(route) { 
    var branch = {}; 
    branch.title = path.basename(route); 
    branch.folder = true; 
    branch.children = []; 

    var files = fs.readdirSync(route); 
    var size = files.length; 

    for (var i = 0; i < size; i++) { 
     var file = files[i]; 
     var concatPath = path.join(route, file); 

     if (fs.lstatSync(concatPath).isDirectory()) 
      branch.children.push(getFolderContents(concatPath)); 
     else 
      branch.children.push({ 
       "title" : path.basename(file), 
       "path" : file 
      }); 
    } 

    return branch; 
} 

我感謝所有的投入!

編輯:

添加了異步代碼嘗試。沒有完全工作。只收到樹的一部分。

exports.browse2 = function(request, response) { 
     getFolderContents(
       'C:\\Users\\AccountName\\folder1\\folder2\\folder3\\test\\', 
       function(tree) { 
        response.send(tree); 
       }); 
    }; 

function getFolderContents(route, callback) { 
    var branch = {}; 
    branch.title = path.basename(route); 
    branch.folder = true; 
    branch.children = []; 

    fs.readdir(route, function(err, files) { 
     files.forEach(function(file) { 
      var concatPath = path.join(route, file); 

      fs.lstat(concatPath, function(err, stats) { 
       if (stats.isDirectory()) 
        branch.children.push(getFolderContents(concatPath, callback)); 
       else 
        branch.children.push({ 
         "title" : path.basename(file), 
         "path" : file 
        }); 

       callback(branch); 
      });   
     }); 
    }); 
} 

回答

0

我設法讓它工作。這裏是我的答案我自己的問題:

  1. 這是更好地執行任務異步,因爲這樣做,否則將意味着該應用程序將在收到他們的答覆,直到後來的請求已作出迴應來阻止其他用戶。

  2. 將同步代碼轉換爲異步代碼的方法是使用並行循環。針對我的具體情況的代碼是這樣的:

    var path = require('path'); 
    var fs = require('fs'); 
    
    exports.browse2 = function(request, response) { 
    getFolderContents(
         'C:\\Users\\AccountName\\folder1\\folder2\\folder3\\test\\', 
         function(err, tree) { 
          if (err) 
           throw err; 
          response.send(tree); 
         }); 
    }; 
    
    function getFolderContents(route, callback) { 
    var branch = {}; 
    branch.title = path.basename(route); 
    branch.folder = true; 
    branch.children = []; 
    
    fs.readdir(route, function(err, files) { 
        if (err) 
         return callback(err); 
        var pending = files.length; 
        if (!pending) 
         return callback(null, branch); 
        files.forEach(function(file) { 
         var concatPath = path.join(route, file); 
         fs.lstat(concatPath, function(err, stats) { 
          if (stats && stats.isDirectory()) { 
           getFolderContents(concatPath, function(err, res) { 
            branch.children.push(res); 
            if (!--pending) 
             callback(null, branch); 
           }); 
          } else { 
           branch.children.push({ 
            "title" : path.basename(file), 
            "path" : file 
           }); 
           if (!--pending) 
            callback(null, branch); 
          } 
         }); 
        }); 
    }); 
    } 
    

由於用戶「chjj」他對這一主題的類似問題的回答:node.js fs.readdir recursive directory search

並感謝用戶「丹Smolinske」爲指引我進入主題。

+0

我努力將此代碼格式化爲10分鐘。我想,該系統不喜歡我的語法。也許主持人可以解決這個問題? –

+0

此方法有效:http://grammerjack.blogspot.jp/2010/12/asynchronous-directory-tree-walk-in.html – arcseldon

1

您遇到的基本問題是,當您使用異步調用時,不能只將函數分配給函數的返回值。異步的完整點是該功能不會等待。因此,例如:

function get_data(a) { 
    var data = some_async_call(a); 

    //at this point, data is undefined because execution won't wait on the calls to finish 

    data.do_something(); // this breaks because of the above 
} 

因此,你要做的就是通過一個匿名函數異步函數調用的回調,以及異步函數調用,一旦操作實際完成該功能。上面的例子會變成這樣:

function get_data(a) { 
    some_async_call(a, function(data) { 
     data.do_something(); 
    }); 
} 

function some_async_call(variable, callback) { 
    call_async({ 
     data: variable, 
     success: callback 
    }); 
} 

而在你的情況應該是這樣認爲:

exports.browse2 = function(request, response) { 
    getFolderContents('C:\\Users\\AccountName\\folder1\\folder2\\folder3\\test\\', function(tree) { 
     response.send(tree); 
    }); 
}; 

function getFolderContents(route, callback) { 
    var branch = {}; 
    branch.title = path.basename(route); 

    ... 

    callback(branch); 
} 

如果你熟悉setTimetout,這是如何工作 - 設計模式是傳遞一個完成工作的匿名函數,然後在數據/信息實際可用時執行該函數。

+0

感謝您的建議。我仍然很困惑這件事。 –

+0

格式化有點搞砸 - 現在應該看起來更好。我還會就這個問題添加更一般的解釋。 –

+0

它開始對我更有意義。我編輯了我的原始問題,以顯示我目前擁有的異步代碼。目前它只能部分工作。看起來,我的樹只有一部分最終發送給了發送的響應。我感謝你的解釋。 –