JavaScript Promise 与 AJAX

Mat*_*ttG 5 javascript ajax

我正在尝试将一系列 AJAX 请求写入字典。我正在尝试为此使用承诺,但是我要么错误地编写了承诺语法,要么我认为可能发生的是该函数实际上正在完成(for 循环已完成,并且 AJAX 请求已发送)但 AJAX 请求仍在没有回来。因此,这仍然返回一个空字典。

let dict = {};
let activeMachines = ["41", "42", "43"];
let dataPromise = new Promise (function (resolve, reject)
{
 for (let i = 0; i < activeMachines.length; i++)
 {
  let machineID = activeMachines[i]
  let getAPIData = new XMLHttpRequest();
  let url = 'http://127.0.0.1:8000/processes/apidata/' +machineID + '/';
  getAPIData.open('GET', url);
  getAPIData.send();
  getAPIData.onload = function()
  {
   let APIData = JSON.parse(getAPIData.responseText);
   dict['machine_' + machineID] = APIData[0].author_id;
   dict['temp' + machineID] = APIData[0].tempData; //get value
   dict['humid' + machineID] = APIData[0].humidData;
   timeValue = String((APIData[0].dateTime));
   dict['time' + machineID] = new Date(timeValue);
   console.log("done");
  }
 }
 resolve();
});

dataPromise.then(function() {console.log(dict);});
Run Code Online (Sandbox Code Playgroud)

当所有 XMLHTTPRequests 都返回时,有没有办法“感知”?

jer*_*red 7

@Rafael 的答案会起作用,但它并不能说明出了什么问题,因为你正在尝试理解 Promise 的概念并自己编写一个。

从根本上来说,我认为你的方法有两个失误:1.创建一个单独的 Promise 来处理对所有任意“activeMachines”列表的调用,2.将你的resolve()调用放在错误的位置。

通常 Promise 看起来像这样:

const myPromise = new Promise(function(resolve, reject) {
  doSomeAsyncWork(function(result) {
    // Some kind of async call with a callback function or somesuch...
    resolve(result);
  });
}).then(data => {
  // Do something with the final result
  console.log(data);
});
Run Code Online (Sandbox Code Playgroud)

您可以使用以下命令模拟某种任意异步工作setTimeout()

const myPromise = new Promise(function(resolve, reject) {
  // Resolve with "Done!" after 5 seconds
  setTimeout(() => {
    resolve("Done!");
  }, 5000);
}).then(data => {
  console.log(data); // "Done!"
});
Run Code Online (Sandbox Code Playgroud)

然而,您的原始代码将调用resolve()放在一个奇怪的地方,甚至没有向其传递任何数据。它看起来有点相当于这个:

const myPromise = new Promise(function(resolve, reject) {
  // Resolve with "Done!" after 5 seconds
  setTimeout(() => {
    // Doing some work here instead of resolving...
  }, 5000);
  resolve();
}).then(data => {
  console.log(data); // This would be "undefined"
});
Run Code Online (Sandbox Code Playgroud)

您在原始代码中执行 a 的位置console.log("done");实际上是您应该执行 a 的位置resolve(someData);

您还尝试在 Promise 的异步函数内部进行副作用工作,这非常奇怪,并且与 Promise 应该如何工作相反。Promise 应该执行并完成异步工作,然后结果数据来解析——实际上是用.then()链来解析。

此外,您不应在 Promise 内部执行多个异步调用,而应对其进行泛化,使其可重用并仅封装单个网络请求。这样你就可以触发多个异步 Promise,等待它们全部解析,然后执行某些操作。

const activeMachines = ["41", "42", "43"];

// Make a reusable function that returns a single Promise
function fetchAPI(num) {
  return new Promise(function(resolve, reject) {
    const getAPIData = new XMLHttpRequest();
    const url = "http://127.0.0.1:8000/processes/apidata/" + num + "/";
    getAPIData.open("GET", url);
    getAPIData.send();
    getAPIData.onload = function() {
      const APIData = JSON.parse(getAPIData.responseText);
      const resolveData = {};
      resolveData["machine_" + num] = APIData[0].author_id;
      resolveData["temp" + num] = APIData[0].tempData; //get value
      resolveData["humid" + num] = APIData[0].humidData;
      timeValue = String(APIData[0].dateTime);
      resolveData["time" + num] = new Date(timeValue);
      resolve(resolveData);
    };
  });
}

// Promise.all() will resolve once all Promises in its array have also resolved
Promise.all(
  activeMachines.map(ea => {
    return fetchAPI(ea);
  })
).then(data => {
  // All of your network Promises have completed!
  // The value of "data" here will be an array of all your network results
});
Run Code Online (Sandbox Code Playgroud)

APIfetch()很棒,您也应该学习使用它——但前提是您了解 Promise 实际运作方式背后的理论和实践。:)