2014-09-28 30 views
1

我已經經歷了這個問題。 Are recursive AJAX calls a bad idea? 賈斯汀尼斯納提供的答案很好(通過使用承諾)但我的問題有點不同。 我想遞歸調用10 ajax calls。當第一個Ajax調用完成一樣,使我的數據,我認爲(通過Ajax調用提供),並在同一時間我會打電話給第二AJAX call.So我的代碼示例如下所示:遞歸地進行多個AJAX調用是個壞主意

(function() { 
    var downloadAsync = function(url, callback) { 
     var httpRequest; 
     if (window.XMLHttpRequest) { 
      httpRequest = new XMLHttpRequest(); 
     } else if (window.ActiveXObject) { 
      httpRequest = new ActiveXObject("Microsoft.XMLHTTP"); 
     } 
     httpRequest.onreadystatechange = function() { 
      if (httpRequest.readyState === 4 && httpRequest.status === 200) { 
       callback(httpRequest.responseText); 
      } 
     } 
     httpRequest.open("GET", url, true); 
     httpRequest.send(); 
    } 

    function renderData(data) { 
     //data render logic   
    } 
    downloadAsync("mathmatics.json", function(response) { 
     renderData(response); 
     downloadAsync("science.json", function(response) { 
      renderData(response) 
      downloadAsync("english.json", function(response) { 
       renderData(response); 
       .................................... 
      }); 
     }); 
    }); 

})(); 

我想盡可能快地呈現每個數據。所以每次調用Ajax時,我都會渲染這些數據。 這裏是我的問題:

有沒有更好的做到這一點?在這種情況下,我可以使用promises嗎? (渲染數據 是必要儘快)。如果是的話,而不是如何以及如果不是,那麼做這種呼叫的最佳方式是什麼。

  1. 注意:在ajax成功上呈現數據是我的首要任務。
  2. 編輯 - 瀏覽器支持 - 最新的Chrome,Firefox和IE-11。
  3. 編輯 - 根據意見改進:
var array = ["mathematics.json", "science.json", "english.json"]; 
for (var i = 0; i < array.length; i++) { 
    downloadAsync(array[i], renderData); 
} 

function renderData(data) { 
    console.log(data); 
    } 
+1

因爲你沒有發送任何數據,是什麼原因需要擺在首位的嵌套調用?如果只是爲了保持它們的順序,可以更快地發送它們,並使用承諾來保持順序 – charlietfl 2014-09-28 16:48:28

+0

如果您只是保持數據所在的位置的順序,則可以在簡單的循環中調用所有的ajax函數,並且瀏覽器將排隊但它們當然不會按順序完成,你必須自己保留這個順序,但即使沒有承諾,也很容易,只需將一個索引傳遞給'renderData'函數來知道什麼請求已完成等。 – adeneo 2014-09-28 16:50:59

+0

@charlietfl對不起我的錯誤,編輯了這個問題。 – Anshul 2014-09-28 16:51:46

回答

2

嵌套Ajax調用工作。也有一些缺點,但:

  • 如果你做真正的錯誤處理,就可以得到多個嵌套Ajax調用相當混亂,你往往最終在嵌套的每一層重複錯誤處理。
  • 在一些人看來,深度嵌套會導致更少的可讀的代碼比其他技術
  • 如果嵌套任何代碼都可以拋出異常,你需要大量的異常處理程序去適當地捕捉所有的異常,而且很難傳播乾淨的錯誤 - 因爲這些是異步回調,你不能只在一個地方捕捉異常。

見編輯在回答結束現在這個問題的意圖已經闡明

至於其他的方法可以做到這一點,有一定的優勢,使用的承諾。由於您的調用都不依賴於前一組調用,而只是想按照正確的順序插入結果,所以通過一次發送所有ajax請求,然後將序列化結果顯着提高端到端時間按順序排列。這可以通過手動編碼完成,也可以通過承諾輕鬆完成。

你不說什麼答應你打算使用庫(有幾個),但這裏有一個使用藍鳥(儘管代碼將是類似的或與其他圖書館相同)來完成:

(function() { 
    // downloadAsync now returns a promise rather than uses a callback 
    function downloadAsync(url) { 
     return new Promise(function(resolve, reject) { 
      var httpRequest = new XMLHttpRequest(); 
      httpRequest.onreadystatechange = function() { 
       if (httpRequest.readyState === 4) { 
        if (httpRequest.status === 200) { 
         resolve(httpRequest.responseText); 
        } else { 
         reject(httpRequest.status); 
        } 
       } 
      } 
      httpRequest.open("GET", url, true); 
      httpRequest.send(); 
     } 
    } 

    function renderData(data) { 
     //data render logic   
    } 
    var items = ["mathmatics.json", "science.json", "english.json"]; 
    var promises = items.map(function(path) { 
     return downloadAsync(path); 
    }); 

    // Promise.all collects all the promise results and 
    // calls .then only when all the promises have completed 
    Promise.all(promises).then(function(data) { 
     data.forEach(renderData) 
    }).catch(function(e) { 
     // handle errors here 
    }); 

})(); 

這具有它一次請求所有數據的性能優勢,但會以原始請求順序處理結果。與序列化相比,這縮短了端到端時間,就像使用請求響應請求響應請求響應一樣。這從request-request-request和Promise開始。所有這些工作都是爲了讓我們按照我們要求的順序將結果按照正確的順序進行處理。


如果你想盡快顯示任何列,你甚至不用等待所有完成和代碼的第二部分可以是這樣:

// note we are passing an index here so you know which column it is in case that isn't 
// already specified in the data 
function renderData(index, data) { 
    //data render logic   
} 

// are you sure you want a leading/on only one of these three? 
var items = ["mathmatics.json", "science.json", "english.json"]; 
items.forEach(function(value, index) { 
    downloadAsync(value).then(function(data) { 
     renderData(index, data); 
    }); 
}); 

承諾在這裏沒有讓你受益,因爲你可以用你的回調機制編寫類似的結構。


沒有用,你可以只使用你原來的downloadAsync()功能,做到這一點:

downloadAsync("mathmatics.json", renderData); 
downloadAsync("science.json", renderData); 
downloadAsync("english.json", renderData); 

這將啓動並行三個立刻呈現每個人的數據到達。


或者,如果你有三多,你把文件名任意長度的數組,你可以這樣做:

["mathmatics.json", "science.json", "english.json"].forEach(function(item) { 
    downloadAsync(item, renderData); 
}); 
+0

@pandit - 注意:根據您定位的瀏覽器版本,您可能需要使用Bluebird或Q等Promise庫來保證承諾支持。 – jfriend00 2014-09-28 18:04:50

+0

,我有10列,我在列中顯示每個ajax調用的數據,我的想法是儘快顯示數據。這就是爲什麼我這樣做。在你的方法中,只有當所有的Ajax調用完成後,我才能渲染整個數據。 – Anshul 2014-09-28 18:07:09

+0

@pandit - 我這樣編碼,因爲這就是你原來的代碼的工作原理(它一次一個),我假設你想這樣。如果要求或願望不同,它不一定是那樣。我可以在我的答案中添加一個這樣的例子。 – jfriend00 2014-09-28 18:11:45

0

既然你正在做新的瀏覽器 - 你的生活會是一個lot更簡單的承諾。

自IE6以來,您正在檢查不相關的事情,您可以大大簡化您的工作。

方法如下:

function downloadAsync(url){ 
    return new Promise(function(fulfill, reject){ 
     var xhr = new XMLHttpRequest; 
     xhr.open("GET", url); 
     xhr.onload = function(){ resolve(xhr.responseText); }); 
     xhr.onerror = reject; 
     xhr.send(); 
    }); 
} 

不用了,檢查的XMLHttpRequest,對於狀態檢查沒有需求,一個簡單的onload事件 - 注意,我們還增加了onError的,所以我們不沉默的錯誤。

現在,讓我們來下載所有三個同時:

// your pages 
var pages = ["mathmatics.json", "science.json", "english.json"] 
// your downloads and renders 
var promises = pages.map(downloadAsync). 
        /*map(JSON.parse).*/ 
        map(renderData); 
Promise.all(promises).then(function(){ 
    // code here runs when it's all done. 
}); 
相關問題