在异步XMLHttpRequest的数据可用之后执行代码

时间:2016-07-13 12:14:27

标签: javascript json asynchronous xmlhttprequest

我需要从服务器加载一个JSON文件,稍后我会用它来填充网站上的内容。使用XMLHttpRequest加载JSON文件应该是异步的,并且可以尽快发生。然而,填充内容需要加载DOM。

现在,我调用xhr.open('GET', 'records.json', false)使请求同步。这需要花费更多时间来加载和解析JSON,而不是浏览器加载DOM。当发生这种情况时(即连接速度很慢),将加载DOM,DOMContentLoaded事件监听器中的代码将在仍然listData的{​​{1}}上执行。坏。

如何使用异步undefined并同时在XMLHttpRequest上执行我的代码?我想在DOMContentLoaded完全加载后执行我的代码(即完成listData)并且DOM可用。当两个条件都满足时,我很高兴。

JSON.parse()

2 个答案:

答案 0 :(得分:1)

当我需要等待几个异步事件时,我的个人方法通常是这样的:

const EVENT0 = 0x1;
const EVENT1 = 0x2;
const ALL_READY = 0x3;

var ready = 0;
init();

function init() {
  asyncRequest0();
  asyncRequest1();

  var waitFunc;

  (waitFunc = function() {
    if(ready == ALL_READY) {
      goOn();
    }
    else {
      setTimeout(waitFunc, 10);
    }
  })();
}

function goOn() {
  console.log('Here we go!');
}

function asyncRequest0() {
  // some callback will do:
  ready |= EVENT0;
}

function asyncRequest1() {
  // some callback will do:
  ready |= EVENT1;
}

所以基本上,每个异步事件都会在“准备好”中设置一个位。一旦工作完成,就变量。 waitFunc()函数将耐心地等待所有事件完成(无论以何种顺序)并调用goOn()函数。

现在,应用于您的代码:

const DOM_READY = 0x1;
const XHR_READY = 0x2;
const ALL_READY = 0x3;

var ready = 0;
var listData;

init();

function init() {
  document.addEventListener("DOMContentLoaded", function() {
    ready |= DOM_READY;
  });

  var xhr = new XMLHttpRequest();

  xhr.open('GET', 'records.json', false);
  xhr.addEventListener("load", function() {
    if (xhr.readyState === 4) {
      if (xhr.status === 200) {
        listData = JSON.parse(xhr.responseText);
      } else {
        listData = false;
        console.error('Error: ' + xhr.status + ' ' + xhr.statusText);
      }
      ready |= XHR_READY;
    }
  });
  xhr.addEventListener("error", function() {
    listData = false;
    ready |= XHR_READY;
    console.error('Error: ' + xhr.status + ' ' + xhr.statusText);
  });
  xhr.send(null);

  var waitFunc;

  (waitFunc = function() {
    if (ready == ALL_READY) {
      goOn();
    } else {
      setTimeout(waitFunc, 10);
    }
  })();
}

function goOn() {
  console.log('Here we go!');
  // do something with listData
}

这里只有2个事件不需要位掩码,但它是一次测试多个事件的便捷方式。

答案 1 :(得分:1)

您可以使用promise和async get请求,并将成功返回的数据附加到DOMContentLoaded回调中可用的内容中,您可以在其中重复检查数据是否已分配。



let myData;

let doAsyncOperation = (param) => {
  if ( window.Promise ) {
    let promise = new Promise( (resolve, reject) => {

      // Do your async request here...
      window.setTimeout(() => {
        // resolve the promise with successfully returned data from get req.
        resolve(`Hello ${param}`)
      }, 1000);

      // reject the promise if your request returns an error
      if (typeof param !== "string") reject("param must be a string");

    })
    return promise;
  } else {
  	console.log("Sorry no promise for you, use a fallback ")
  }
} 

doAsyncOperation("Foo !").then(
  // on success do something with your data.
  (data) =>  myData = data,
  (err) => console.log(err)
);

// Inside DOMContentLoaded callback check if myData is available.
document.addEventListener("DOMContentLoaded", (event) => {
  let loop = () => {
  	(myData) ? console.log(myData) : window.setTimeout(loop, 100);
  };
  loop();
});