首页 > 解决方案 > 如何使用 fetch() 使用来自服务器的数据填充变量?

问题描述

我有一个从 Open Weather API 获取数据并将一些值分配给一些 HTML 元素的 innerText 属性的函数。这部分工作正常。

但我还需要将其中一个值 ( data["main"]["temp"]) 存储到对象 () 的属性中userData.temp

//Function to get data from Open Weather
const getWeatherData = () => {
  let zipInputValue = document.getElementById("zip").value;
  const weatherUrl = `http://api.openweathermap.org/data/2.5/weather?zip=${zipInputValue},${weatherCountryCode}&units=metric&appid=`;
  fetch(weatherUrl + weatherApiKey).then((res) => {
    if (res.status != 200) {
      console.log("Looks like there's been a problem.");
      return;
    }
    res.json().then((data) => {
      descriptionElement.innerText = "Weather: " + data["weather"][0]["description"];
      currenttempElement.innerText = "Temperature:" + data["main"]["temp"] + " °C";
      userData.temp = data["main"]["temp"];
      mintempElement.innerText = "Min.:" + data["main"]["temp_min"] + " °C";
      maxtempElement.innerText = "Max.:" + data["main"]["temp_max"] + " °C";
    });
  });  
  console.log(userData.temp);
};

在我的代码末尾,有一个generate()由点击事件触发的函数,它调用该函数getWeatherData(),然后userData.temp通过调用该函数将其发布到服务器postProjectData(userData)

/*---------- Post Data to the Server ---------- */

const postProjectData = async (userData) => {
  const rawResponse = await fetch("http://localhost:8080/addData", {
    method: "POST",
    body: JSON.stringify(userData),
    headers: {
      Accept: "application/json",
      "Content-Type": "application/json",
    },
  });
  const response = await rawResponse.json();
  return response;
};

/*---------- Generate Entry ---------- */

const btn = document.getElementById("generate");
btn.addEventListener("click", generate);

function generate() {
  getWeatherData();
  console.log("test");

  userData.date = newDate;
  userData.userResponse = getUserResponse();

  postProjectData(userData);

  getProjectData();
}

但是,当第一次调用此单击事件时,该属性对服务器变为空。第二次,它与前一次迭代的值一致。意思是,它也是落后的一个迭代。

我假设这是因为当浏览器进入fetch内部getWeatherData()时,因为它是一个异步函数,它会继续postProjectData(userData);只有在那之后,才fetch实际填充属性。

我想对了吗?以及如何在正确的迭代中填充属性?

标签: javascriptasynchronousfetch

解决方案


您的问题是您没有等待数据到达以将其发布到服务器。你可以重构getWeatherDatagenerate做到这一点。

第一件事是返回一个 Promise ,getWeatherData这样你就可以等待数据被获取:

const getWeatherData = () => new Promise((resolve, reject) => {
  let zipInputValue = document.getElementById("zip").value;
  const weatherUrl = `http://api.openweathermap.org/data/2.5/weather?zip=${zipInputValue},${weatherCountryCode}&units=metric&appid=`;

  fetch(weatherUrl + weatherApiKey).then((res) => {
    if (res.status != 200) {
      console.log("Looks like there's been a problem.");
      return reject();
    }
    res.json().then((data) => {
      descriptionElement.innerText = "Weather: " + data["weather"][0]["description"];
      currenttempElement.innerText = "Temperature:" + data["main"]["temp"] + " °C";
      userData.temp = data["main"]["temp"];
      mintempElement.innerText = "Min.:" + data["main"]["temp_min"] + " °C";
      maxtempElement.innerText = "Max.:" + data["main"]["temp_max"] + " °C";

      resolve();
    });
  });  
  console.log(userData.temp);
});

这里的要点是解决/拒绝 Promise 以让函数调用者(在这种情况下generate)获取数据。

然后我们重构generate

async function generate() {
  await getWeatherData();
  console.log("test");

  userData.date = newDate;
  userData.userResponse = getUserResponse();

  postProjectData(userData);

  getProjectData();
}

这个想法是转换generate成一个异步函数,让它等待数据到达( getWeatherData),以便调用postProjectData.


推荐阅读