2016-09-20 31 views
0

我有到位被拆分大型查詢到管理的小塊,然後用一個簡單的AJAX方法吐出了這一點的工具。 AJAX表單的目的地只是一個將某些表單數據委託給函數的腳本,包括處理哪個「塊」。未能延時功能,直到後for循環已全面完成

<script>     

var passes = Math.ceil($max/$offset); 

for (i = 0; i < passes; i++) 
{ 

    $.ajax({ 
     type: 'POST', url: 'do.php?p=' + i, data: $('#form" . $i . "').serialize(), 
    success: function(data){ 
     $('#update" . $i . "').append(data); 
    } 
    }); 
} 
</script> 

,因爲這可以重複幾次,我一直在尋找爲執行循環何時腳本(即本身的功能)已完成。

由於這不是什麼太時髦,我認爲這將是添加if(i == passes -1) { alert('test');}if(i == passes -1) { alert('test');}到循環的結束,像這樣的一個簡單的例子:

for (i = 0; i < passes; i++) { 

    $.ajax({ 
     type: 'POST', url: 'do.php?p=' + i, data: $('#form" . $i . "').serialize(), 
    success: function(data){ 
     $('#update" . $i . "').append(data); 
    } 
    }); 

    if(i == passes -1) { alert('test');} 

} 

....但它加載這個作爲在頁面加載之前,在循環之前。

同樣,在之後添加一個簡單功能循環也獲得了相同的結果。

我本來以爲(但我在JS挺新鮮的),它會試圖執行的「i」的第二個實例之前完成一個循環,但它似乎並沒有這樣做 - 頁面的行爲像所有請求都會立即發送,完成循環,執行代碼,然後允許「成功」內的函數在自己的時間內回顯。這似乎更加明顯,因爲它有時會在第一次之前追加第二次迭代i的結果。

問題...

1)因爲我已在我如何構成的循環,考慮到目的的錯誤?

2)爲什麼循環似乎在循環之後執行代碼時,它看起來像它仍然會在處理循環本身?

我試圖實現

每個循環應該執行MySQL查詢,回放功能的HTML輸出,然後移動到下一個前打印出來。它確實做到了99%正確,只是偶爾出現的問題並不總是按順序排列。

畢竟循環已經完成,並追加到容器中,我想運行一些代碼來確認操作完成。

許多在此先感謝,希望這是不夠清楚

+1

看看:[爲什麼我的變量在函數內部修改後沒有改變? - 異步代碼引用](http://stackoverflow.com/questions/23667086/why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron) – Andreas

+1

使用承諾。或者對於簡單的ajax,使用Callback。 –

+0

您可以對函數使用遞歸調用,將其添加到$ .ajax的成功參數中。這會按照您希望的順序加載所有內容。 –

回答

1

這是針對您的問題的「承諾」解決方案。

首先,分解每一個進入,做一個工作單元的功能:

function makePass(i) { 
    return $.ajax({ 
     type: 'POST', url: 'do.php?p=' + i, data: $('#form' + i).serialize() 
    }).then(function(data) { 
     $('#update' + i).append(data); 
    }); 
} 

然後你就可以做出一個通用的函數,僞遞歸將調用所提供的功能所需的號碼,主叫每次用當前通號它,最後返回一個新的「解決」的承諾一次通已經完成:

function makeNPasses(f, n) { 
    var i = 0; 
    return (function loop() { 
     if (i < n) { 
      return f(i++).then(loop); 
     } else { 
      return Promise.resolve(); 
     } 
    })(); 
} 

然後,您可以註冊一個處理程序,一旦一切都做,要調用:

var passes = Math.ceil($max/$offset); 

makeNPasses(makePass, passes).then(function() { 
    console.log("All done!"); 
}); 
+0

Brilliant。完全符合計劃。我必須研究它才能真正理解這是如何完成的,但它看起來像是一個絕妙的解決方案。謝謝! –

+0

@ChrisJ真正的「神奇」在於'loop()'函數中,它可以重複調用自己所需的次數,並且還可以確保AJAX調用不會全部並行進行。 – Alnitak

-1

發出Ajax請求同步:

所有Ajax請求:

$.ajaxSetup({ async: false }); 

個人:

$.ajax({ 
    async: false, 
    ......... 
}); 
+0

不,不會*使用同步請求 – Alnitak

0

的Javascript有一個異步流程。它不會等待上述請求獲取da ta從某個地方......相反,它只是連續發射聲明。

爲了避免這種情況,有3個選項。

  1. 理想的方法是使1個單HTTP請求到服務器,並獲得在JSON陣列的形式的所有數據。這將更加高效,簡單和省時,並遵循最佳實踐。
  2. 進行ajax的異步調用。你會在這個答案jQuery ajax success anonymous function scope得到有關它的好信息。但是,再次推薦回調,不要做異步錯誤。相反,.when().then()更容易..因爲最終他們也是回調。

  3. 遞歸函數可以幫助你完成這樣的任務。這是一種骯髒的方法,因爲ES5不允許使用遞歸函數進行更深入的迭代。但ES6確實允許它進行10000次迭代。但它不是一個好方法。它增加了開銷和瓶頸你的頁面加載。

+0

我將請求分成塊的原因是每個塊在數據庫表中處理大約2500行。在單個請求中執行此操作時,會導致內存和服務器性能方面的巨大問題,因爲一個請求可能導致250,000多個結果行。 該AJAX是相當快速和功能,但剛剛出現問題。 這是否有助於澄清爲什麼我這樣做? –

+0

當然可以。 ! @ChrisJ –

+1

但是.promise()系統肯定會對這樣的應用程序有好處。 http://www.htmlgoodies.com/beyond/javascript/making-promises-with-jquery-deferred.html –

-1

AJAX調用是異步的,因此它們不能用在循環結束之前成功(如JavaScript是非阻塞)。事實上你所想要做的是AJAX調用後,不只是循環(這是同步)後進行動作,所以我會或者使用承諾或鏈接或聚合成功的事件,如以下建議:

var passes = Math.ceil($max/$offset); 
for (i = 0; i < passes; i++) { 
    $.ajax({ 
     type: 'POST', 
     url: 'do.php?p=' + i, 
     data: $('#form' + i).serialize(), 
     success: function(data){ 
      $('#update' + i).append(data); 
      resolve(); 
     }, 
     error: reject 
    }); 
} 

var resolved = 0; 
function resolve() { 
    if(++resolved >= passes) { 
     alert('test'); 
    } 
} 

function reject() { 
    alert('One of AJAX requests failed'); 
} 
+0

不幸的是,這仍然不起作用。 '測試'提示將隨機出現在結果集內。經過8次迭代測試,它在循環結束前的一個隨機點發出警報 –

+0

這是不正確的代碼 - 循環內的「i」沒有正確綁定到當前迭代計數,當它用於'成功'處理程序。 – Alnitak

+0

這可能是我的錯,因爲使用php'$ i'作爲父迭代,而JS'i'作爲我的子迭代,這可能使它看起來像在這種情況下是同一個,拋棄了作者答案 –