2015-09-09 70 views
0

我在服務器上有一個文件夾層次結構。我想循環遍歷這個層次,並且遞歸地,當找到一個文件時,調用一個自定義方法。Promise&遞歸,如何處理沒有回調的找到的項目?

現在,我的代碼看起來是這樣的:

searchFile(root, handleFile); 

// loop over all folders recursively, then handle files 
function searchFile(item, callbackWhenFile) { 
    if (itIsFolder(item)) { 
     $http.get("api.call.com/children/" + item.id) 
       .then(function (children) { 
        angular.forEach(children, 
         function (child) { 
          searchFile(child, callbackWhenFile); 
         }); 
       }); 
    } 
    else { 
     // this is not a folder, so this is a file 
     callbackWhenFile(item); 
    } 
} 

回調是用來代替承諾的事實是不是一件好事。

但我試圖找到一種方法,使它與承諾一起工作,沒有機會。

在一個理想的解決方案,我想這樣做:

searchFile(root).then(function (file) { 
    handleFile(file) 
}); 

我看着q.all $,$ q.when,但似乎沒有適應這種情況。我們不知道我們將要使用的文件數量,這使得問題變得困難。

任何人都有一個想法如何解決這個問題?

編輯答案

Promises are not the way to go.

隨着RxJS和觀察對象,這可以寫成:

getFileStream(root).subscribe(function (file) { 
    handleFile(file); 
}); 

function getFileStream(root) { 
    var source = Rx.Observable.create(function (observer) { 
     observeFiles(observer, root); 
    }); 
    return source; 
} 

function observeFiles(observer, item) { 
    if (itIsFolder(item)) { 
     $http.get("api.call.com/children/" + item.id) 
       .then(function (children) { 
        angular.forEach(children, 
         function (child) { 
          searchFile(observer, child); 
         }); 
       }); 
    } 
    else { 
     observer.onNext(item); 
    } 
} 
+1

更好地重寫服務器的方法。使999請求搜索單個文件?這在現實生活中如何工作? –

回答

3

一個承諾只能解析到一個值。該值可以是一個對象,也可以是一個數組,但最終它是一個單一值 - 不是流。

您的「理想解決方案」被定義爲它確實生成了一個流,這是不可能的。

您可以:

  1. 留下你的代碼,因爲它是。您的回調被異步調用,並且只要有文件需要處理即可。
  2. 更改您的遞歸來組裝單個值。一個平面數組/地圖(對象...)的文件。該值可以在下一個函數(.then(processArray))內同步處理。
  3. 使用像BaconJSRxJS流媒體庫。
-1

下面的代碼應該做的伎倆:

searchFile(root).then(function (files) { 
    function (files) { 
     angular.forEach(files, 
         function (file) { 
          handleFile(file); 
         }); 
    }); 
}); 

// loop over all folders recursively, then handle files 
function searchFile(item) { 
    var deferred = $q.defer(); 
    var files = []; 
    if (itIsFolder(item)) { 
     $http.get("api.call.com/children/" + item.id) 
       .then(function (children) { 
        angular.forEach(children, 
         function (child) { 
          searchFile(child).then(
           function (files) { 
            angular.forEach(files, 
            function (file) { 
             files.add(file); 
            }); 
           }); 
         }); 

         deferred.resolve(files); 
       }); 
    } 
    else { 
     files.add(item); 
     deferred.resolve(files); 
    } 

    return deferred.promise; 
} 
+0

Hi @piyuj,謝謝你的回答。我已經嘗試過類似的東西,但承諾將在找到的第一個文件上解決,所以文件數組將只包含一個項目。進一步發現的文件將不會被處理。 –

+0

如果您通過文件運行搜索,它只會找到一個文件。 但是,如果你在一個文件夾上運行它,遞歸會創建與searchFile所調用的一樣多的promise。並在該塊的當時函數上解析它 'searchFile(child).then( function(files){ angular。forEach(files, function(file){ files.add(file); }); });' – piyuj

+0

@piyuj:的確如此。只有該塊可以用當前'child'文件/目錄的結果解決,並且不會等待所有文件路徑。不要使用延遲反模式,而是使用'$ q.all'。 – Bergi