如何确保XMLHttpRequest在for循环中完成?

Ren*_*mer 1 javascript opengraph facebook-graph-api

我有这个代码可以获取页面上不同文章的共享计数.

我为每个URL打开一个XHR并获取它的图形结果,将响应解析为JSON并获取共享.然后我通过缩写算法运行共享号码以获得更友好的数字.

我遇到的当前问题是,当for循环运行时,它会依次打开所有XHR,然后只进行处理最后一个XHR.不知何故,其他XHR正在被抛弃.

我怎样才能确保获得所有请求的结果?

var counters = document.getElementsByClassName('box-counter');
for (var i = 0, n = counters.length; i < n; i++) {
  var element = counters[i],
    XHR = new XMLHttpRequest();
  element.innerHTML = 'unknown';
  XHR.onreadystatechange = function() {
    if (XHR.readyState == 4 && XHR.status == 200) {
      element.innerHTML = friendlyExpress(
        JSON.parse(XHR.responseText).shares
      );
    }
  }
  XHR.open(
    'GET',
    'http://graph.facebook.com/' + counters[i].parentNode.attributes['data-url'].value,
    /*async*/
    true);
  XHR.send();
}

function friendlyExpress(x, legend, power) {
  legend = 'okmgpt';
  power |= 1024;

  var powerLimit = legend.length - 1,
    powerIndex = 0;

  while (x > (power - 1) && powerIndex < powerLimit) {
    x /= power;
    powerIndex++;
  }
  return Math.round(x) + legend[powerIndex];
}
Run Code Online (Sandbox Code Playgroud)
<div>
  <section data-url="http://highline.huffingtonpost.com/articles/en/amaris-tyynismaa-runner/">
    <h3> Some Article </h3>
    <div class="box-counter"></div>
  </section>
  <section data-url="http://www.greenvilleonline.com/story/news/local/2015/05/07/stephen-colbert-funding-grant-requests-south-carolina-public-school-teachers-donorschoose-crowdfunding-site/70938100/?from=global&sessionKey=&autologin=">
    <h3> Some Article 2</h3>
    <div class="box-counter"></div>
  </section>
  <section data-url="http://www.nytimes.com/2015/05/08/us/politics/iran-bill-republicans.html">
    <h3> Some Article 3</h3>
    <div class="box-counter"></div>
  </section>
</div>
Run Code Online (Sandbox Code Playgroud)

http://jsfiddle.net/ea7qgzv8/

Ted*_*opp 5

问题是,你的onreadystatechange处理程序是指当前值的封闭XHRelement.由于这些在每次循环迭代时都会发生变化,因此每个处理程序在执行时都会引用最新的XHRelement.由于循环可能在第一个请求完成之前退出,因此所有处理程序都引用最后指定的值.为了解决这个问题,你需要捕获的当前值XHRelement宣布处理程序时.最简单的是使用IIFE(您还可以创建一个单独的函数来返回所需的函数,并避免使用错误的变量创建闭包):

XHR.onreadystatechange = (function(elt, req) {
    return function() {
        if (req.readyState == 4 && req.status == 200) {
            elt.innerHTML = friendlyExpress(JSON.parse(req.responseText).shares);
        }
    };
}(element, XHR));
Run Code Online (Sandbox Code Playgroud)