2011-12-21 162 views
3

我使用getPropertyId函數進行ajax調用來獲取數據。我使用回調來獲得結果,然後使用它們。我的問題是,第二個每個循環都在第一個循環結束之前啓動,即使我把它放在函數中。我可以同步我的代碼以在第一個循環結束後啓動第二個循環嗎? 感謝同步代碼

Plugins.DataHelper.getPropertyId(PropertyID, function(data){ 
    //code using data retrived with getPropertyId function 

    $.each(list, function(index,value){ 
    //code "A" containing asynchronous calls 
    }); 
}); 

$.each(filtredList, function(index,value){ 
    //code "B" 
}); 
+0

爲什麼不換代碼B每循環一個函數並在代碼A循環後調用它? – 2011-12-21 14:09:25

+1

我知道的唯一[$ .each()](http://api.jquery.com/jQuery.each/)是同步的。你真的確定把第二個調用放到與第一個調用相同的函數中的'$ .each()'仍然會導致異步行爲嗎? – 2011-12-21 14:10:43

+0

它沒有工作,它在結束代碼A之前撥打電話 – Djoz 2011-12-21 14:13:48

回答

1

這是JavaScript的本質 - 您應該很習慣基於事件的編程,以避免將來出現類似的問題。

基本上類似的東西應該工作:

Plugins.DataHelper.getPropertyId(PropertyID, function(data){ 
    //code using data retrived with getPropertyId function 

    $.each(list, function(index,value){ 
     //code "A" 
    }); 
    $.each(filtredList, function(index,value){ 
     //code "B" 
    }); 
}); 

,除非你正在AJAX調用內部的 「代碼A」。在這種情況下,您運氣不佳,應該更改您的「代碼A」以使用同步調用(通常是一個糟糕的主意),或者重寫代碼以基於事件工作。

一個想法是確定要處理的元素數量,然後在處理每個項目後調用回調。此回調應檢查是否已處理所有項目(通過遞增計數器並將其與要處理的項目數量進行比較 - 此機制與鎖定的工作方式類似)。當函數確定所有項目已經處理時,它會執行一些操作(否則它不會)。

+0

其實我在Ajax調用裏面的「代碼A」,我需要這個調用是在每個循環內,所以我如何安排我的代碼或改變它迫使第二個循環等待第一?我已經與事件工作,但我可以在哪裏提出事件,將包含第二個循環? – Djoz 2011-12-21 15:58:16

+1

@YoussefMAKNI:在函數中隱藏第二個循環並存儲它(現在不要執行它!)。這個函數應該像我提到的那樣檢查鎖的值。然後,在異步處理每個AJAX請求之後,應該更改鎖的值(在成功處理程序中),然後調用回調(仍處於成功處理程序中)。回調將檢查鎖的值,並最終(在它基於該鎖確定所有請求已被處理之後)將執行該循環。得到它了? – Tadeck 2011-12-21 16:04:12

+0

是的,謝謝Tadeck它的作品! – Djoz 2011-12-23 15:30:32

1

你真的可以創建一個syncronised(=阻塞)的要求,但是這是非常糟糕的瀏覽器的行爲。更好的做法是讓回調函數爲你工作,所以當第一個Ajax調用完成時(成功/錯誤),你需要「繼續」代碼。

Plugins.DataHelper.getPropertyId(PropertyID, function(data){ 
    XHRobject.onreadystatechange = function() { 
     if(XHRobject.readyState === 4) { 
      $.each(list, function(index,value){ 
       //code "A" 
      }); 
     } 
    } 
}); 

請注意,這是一個演示原理的簡單示例。既然你也標記了jQuery,你可以通過調用promise對象來使其非常強悍。看起來像

Plugins.DataHelper.getPropertyId(PropertyID, function(data){ 
    $.ajax({}).done(function() { 
     $.each(list, function(index,value){ 
      //code "A" 
     }); 
    }); 
}); 
0

第一個等待直到ajax調用完成。

與此同時,腳本繼續,並每秒排第一。

嘗試在第一個每個循環之後放置第二個。

0

您可以使用傳統的Lock語義

Plugins.DataHelper.lock = false;//release 
Plugins.DataHelper.getPropertyId(PropertyID, function(data){ 
    //code using data retrived with getPropertyId function 

    $.each(list, function(index,value){ 
     Plugins.DataHelper.lock = true;//acquire 
     //code "A" 
     Plugins.DataHelper.lock = false;//release 
    }); 
}); 
while(Plugins.DataHelper.lock) 
    continue;//wait until released 
$.each(filtredList, function(index,value){ 
    //code "B" 
}); 

或者您可以追加一個功能你的Ajax XHR的完成回調之後調用。

var nextF = function(){}; 
Plugins.DataHelper.getPropertyId(PropertyID, function(data){ 
    //code using data retrived with getPropertyId function 

    $.each(list, function(index,value){ 
     //code "A" 
     nextF(); 
    }); 
}); 
nextF = function(){ 
$.each(filtredList, function(index,value){ 
    //code "B" 
}); 
}//You need to pass the scope to the nextF function like nextF.call(scope) where scope is cached somewhere 
+0

你測試過了嗎?我有不好的感覺,它會凍結我的瀏覽器或立即執行「代碼B」,而無需等待結果.. – Tadeck 2011-12-21 14:16:46

+0

Ya第一個會凍結,除非ajax調用釋放鎖。沒有我的任何測試。第二個不冷凍。 – 2011-12-21 14:16:58

1

您應該能夠通過移動第二個「各」調用回調函數裏面像這樣來實現這一目標:

Plugins.DataHelper.getPropertyId(PropertyID, function(data){ 
    //code using data retrived with getPropertyId function 

    $.each(list, function(index,value){ 
    //code "A" 
    }); 

    $.each(filtredList, function(index,value){ 
    //code "B" 
    }); 
}); 

編輯:請閱讀以下文章瞭解更多信息:flow control in javascript

+0

這是行不通的,因爲在「代碼A」中存在AJAX調用 – Djoz 2011-12-21 15:59:41

+0

如果'代碼A'正在進行ajax調用來構建過濾列表,則可以將每個塊合併爲一個塊並在其中執行'代碼B'成功處理程序。 – Darren 2011-12-22 15:05:37