在循环中执行异步XMLHttpRequests,并在所有请求完成后继续

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在循环中执行异步XMLHttpRequests,并在所有请求完成后继续相关的知识,希望对你有一定的参考价值。

我正在尝试在for loop中执行异步XMLHttpRequests,它会加载一堆JSON。

为了确保在调用nextFunction()之前完成所有XMLHttpRequests请求,我使用的是xhr.onreadystatechange。这似乎工作正常,但我的nextFunction()正在最后一个XMLHttpRequest完成之前执行。

为什么会这样?我做错了什么?

var arrCurrency = ['Bitcoin', 'Ethereum', 'Litecoin', 'Ripple'];
arrJSON = [];
createCurrencyArray();

function createCurrencyArray() {

  var count = 0;

  for (var i = 0; i < arrCurrency.length; i++) {

    var url = 'https://api.coinmarketcap.com/v1/ticker/' + arrCurrency[i] + '/?convert=EUR';

    getJSON(url, parseJSON);

    function parseJSON() {
      var a = this.responseText;
      var b = a.slice(1, -1);
      var c = JSON.parse(b);
      arrJSON.push(c);
    }
  }

  function xhrSuccess() {
    this.callback.apply(this, this.arguments);
  }

  function getJSON(url, callback) {

    var xhr = new XMLHttpRequest();
    xhr.callback = callback;
    xhr.onload = xhrSuccess;
    xhr.onreadystatechange = function() {

      if (xhr.readyState == 4) {

        count++;
        console.log('state:' + xhr.readyState + ' JSON-' + count + ' loaded')

        if (count == arrCurrency.length) {
          console.log("Done: All JSONs loaded");
          nextFunction();
        }
      }
    }
    xhr.open("GET", url, true);
    xhr.send(null);
  }
}

function nextFunction() {
  console.log(arrJSON);
  console.log('array length: ' + arrJSON.length);
  console.log('array key 0: ' + arrJSON[0]["id"]);
  console.log('array key 1: ' + arrJSON[1]["id"]);
  console.log('array key 2: ' + arrJSON[2]["id"]);
  console.log('array key 3: ' + arrJSON[3]["id"]);
}
答案

你应该在这里使用promises并在所有请求完成后处理结果。

var arrCurrency = ['Bitcoin', 'Ethereum', 'Litecoin', 'Ripple'], arrJSON = [], all = [];

function nextFunction() {  
  console.log('array length: ' + arrJSON.length);
  arrJSON.forEach((entry,idx)=>{console.log('array-key '+idx+': ' + arrJSON[idx].id); });
  console.log(arrJSON);
}

function parseJSON(jsn) {
    var obj = jsn.slice(1, -1);
    var jsnObj = JSON.parse(obj);
    arrJSON.push(jsnObj);
}
   
for(i=0; i < arrCurrency.length; i++){    
  
    var p = new Promise(function(resolve,reject){  
    var oReq = new XMLHttpRequest();	
	  oReq.addEventListener("load", function(xhr){ resolve(xhr);});
	  oReq.addEventListener("error",  function(b){reject(this);});
	  oReq.open('GET', ['https://api.coinmarketcap.com/v1/ticker/' + arrCurrency[i] + '/?convert=EUR'].join(""), true);
		oReq.send();   
   });
    all.push(p);
} // loop end
  
Promise.all(all).then(values => {
  values.forEach(function(p){parseJSON(p.currentTarget.responseText);});
  nextFunction();
});

以上是关于在循环中执行异步XMLHttpRequests,并在所有请求完成后继续的主要内容,如果未能解决你的问题,请参考以下文章

禁用同源策略/在 WebKit WebViews 中创建跨域 XMLHttpRequests?

在 for 循环中的异步函数调用中有条件地执行回调

JavaScript 实现异步任务循环顺序执行

异步更新队列 nextTick

Promise循环执行多个请求

如何使用 Q.js 在循环中执行异步函数