2011-12-19 50 views
0

我需要一個遞歸函數異步發生,回調完成後會發生回調。我簡化它擺脫了不相關部分(這裏是一個的jsfiddle代碼:http://jsfiddle.net/DgaBg/8/如何在異步recusive方法完全準備好時創建回調?

tree = { 
    "a": { 
     "b": 1, 
     "c": 2 
    }, 
    "d": { 
     "e": { 
      "f": { 
       "g": 3 
      }, 
      "h": 4, 
      "i": 5 
     }, 
     "j": { 
      "k": 6, 
      "l": 7 
     }, 
     "m": 8, 
     "n": 9 
    }, 
    "o": { 
     "p": 10 
    }, 
    "q": 11 
}; 

Watcher = function() { }; 

Watcher.prototype.startDoingAsyncStuff = function(node, callback) { 
    var me = this, 
     key; 

    if(typeof node === "number") { 
     console.log(node); 
    } else { 
     for(key in node) { 
      if(node.hasOwnProperty(key)) { 
       (function(node) { 
        setTimeout(function() { 
         me.startDoingAsyncStuff(node, callback); 
        }, 500); 
       }(node[key])); 
      } 
     } 
    } 
}; 

w = new Watcher(); 

w.startDoingAsyncStuff(tree, function() { 
    console.log("callback 1"); 
}); 

w.startDoingAsyncStuff(tree["d"], function() { 
    console.log("callback 2"); 
}); 

我需要提供給Watcher.startDoingAsyncStuff回調執行recusion完成後,但我不知道如何做到這一點。

這裏的複雜因素是,使用一個簡單的計數器是不可能的,因爲Watcher.startDoingAsyncStuff應該能夠多次執行,而無需等待以前的調用來完成。

任何幫助,將不勝感激。

+0

你願意使用jQuery或類似的圖書館嗎? – glortho 2011-12-19 15:56:24

+0

我是,但我認爲添加jquery有點矯枉過正,只是爲了實現這一點。你會怎麼說我會用jQuery來做這件事? – standardModel 2011-12-19 15:58:11

+0

'$ .Deferred'在這裏會有所幫助(儘管你可以通過創造性的超時來實現)。就像在開始之前創建一個新的$ .Deferred,並在給定時間內沒有設置標誌500毫秒或其他值(儘管可能比您需要的時間更長)中給它一個超時值。每次運行'startDoingAsyncStuff'都會重置該標誌,所以$ .Deferred保持未解析狀態。用$ .Deferreds肯定會有更好的方式,但是,在開始之前計算所有遞歸級別並從計數中減去,將延遲解決爲0或其他值。 – glortho 2011-12-19 16:05:11

回答

2

基本上,分東西,你要提供一個回調,只是通知其上方的水平,它的完成。在更高的層次上,您可以計算您希望收到的「完成」消息數量,一旦獲得該數字,您就可以調用「真實」回調。

我本來有一個計數器的原型,可以這樣做的功能之外,但實際功能是如此簡單,我將其納入功能本身。

Watcher.prototype.startDoingAsyncStuff = function(node, callback) { 
    var me = this, 
     key, 
     jobCount = 0; 

    if (typeof node === "number") { 
     console.log(node); 
     // There's no sub-stuff to do, so we're done here 
     callback(); 
    } else { 
     for (key in node) { 
      if (node.hasOwnProperty(key)) { 
       (function(node) { 
        ++jobCount; 
        setTimeout(function() { 
         // we create a sub-callback to decrement the counter 
         // and run the "real" callback when the counter is back 
         // to 0. 
         // This works as many times as needed, because jobCount 
         // is local and accessed via closure. 
         me.startDoingAsyncStuff(node, function() { 
          if (--jobCount == 0) callback(); 
         }); 
        }, 500); 
       }(node[key])); 
      } 
     } 
    } 
}; 
+0

這樣做的工作,非常感謝你! – standardModel 2011-12-19 18:15:59

0

無需增加額外的超時,一個辦法是做樹的第一遍實際上並不執行任何的主要任務,而是計算resursions的數量。假設你的樹不是很大,你應該可以在不鎖定瀏覽器的情況下同步執行此操作。

然後做第二次通過,以及執行每個主任務asyncronous增量另一個計數器之後;當它與第一關的計數相匹配時,您可以觸發回調。

+0

嗯,我喜歡你答案,但不幸的是,這不適用於我的情況。我發佈的代碼只是一個模型。實際上,我用Node.js遞歸地遍歷一個文件樹,所以先同步地走一遍,然後異步執行實際的任務,只要同步進行每一步操作就需要花費很長時間。 另外:樹可能非常大(比如你的C的整個文件樹:驅動器在Windows上) – standardModel 2011-12-19 16:16:38

+0

OK,以及在這種情況下,通過傑德上述我只能想類似的東西超時。您不需要jQuery,只是另一個超時,用於檢查是否在特定時間段內調用了「startDoingAsyncStuff」(大於最大迭代所需的時間)。如果沒有,你的步行者就完蛋了。 – Graham 2011-12-19 16:20:30

相關問題