Невозможно получить одинаковые результаты с двумя частями похожего XMLHttpRequest - PullRequest
2 голосов
/ 27 апреля 2020

Надеюсь, вы сможете помочь или просто помочь мне понять, почему у меня есть 2 почти одинаковых кодовых блока, где один не делает то, что я ожидаю.

Я пытаюсь сделать несколько вызовов API, где я заполняю переменную данными, которые извлекаются из вызова API. В первом нет никаких проблем, но во втором я не могу заполнить переменную. Я попытался погуглить проблему, и это, кажется, из-за асинхронной природы XmlHttprequests. Но опять же, я не понимаю, почему одно решение работает, а другое нет.

Решение, которое работает:

// Get JSON and convert it to an object
var obj;
const Http = new XMLHttpRequest();
const url = "https://type.fit/api/quotes";

Http.open("GET", url);
Http.send();

Http.onreadystatechange = function () {
  if (this.readyState == 4 && this.status == 200) {
    obj = JSON.parse(Http.responseText);
  }
};

В этом решении я могу получить данные, заполнить переменную obj и использовать ее глобально.

ссылка на решение: https://codepen.io/Kfriis/pen/QWjGZmx

Решение, которое не работает:

//function that takes a currency in capital letters and returns 
  var rates;
  var currency = 'gbp';
  const currencyString = currency.toUpperCase();
  const API = "api.frankfurter.app"
  const URL = `https://${API}/latest?amount=1&from=${currencyString}&to=DKK`
  
  const http = new XMLHttpRequest();
  
  http.open("GET", URL);
  http.send();
  
  http.onreadystatechange = function() {
      if (this.readyState == 4 && this.status == 200) {
        rates = JSON.parse(http.responseText);
        
      }
  };
  console.log(rates)

По какой-то причине это не работает. Я не понимаю, почему переменная ставок не заполняется, поскольку запрос для первого фрагмента кода практически одинаков. Я пришел к мысли, что данные, отправленные с двух конечных точек API, могут в некотором роде отличаться. Потому что, если бы это было только из-за асинхронных запросов, оба фрагмента кода должны возвращать undefined.

Ссылка https://codepen.io/Kfriis/pen/VwvpKmd

Я надеюсь, что кто-то сможет пролить свет на это. Я должен делать что-то не так во втором фрагменте, потому что я могу console.log () изнутри onreadystatechange, но не снаружи. Что заставило меня долгое время полагать, что это была ограниченная проблема.

1 Ответ

1 голос
/ 27 апреля 2020

Ваш код работает. Однако вы регистрируете console.log(rates) вне функции http.onreadystatechange, что означает, что вы регистрируете тарифы до того, как получите ответ. Если вы измените кодовый блок

 http.onreadystatechange = function() {
      if (this.readyState == 4 && this.status == 200) {
        rates = JSON.parse(http.responseText);

      }
  };
  console.log(rates)

на

 http.onreadystatechange = function() {
      if (this.readyState == 4 && this.status == 200) {
        rates = JSON.parse(http.responseText);
        console.log(rates)
      }
  };

, он должен работать.

Вот рабочий пример кода, если вы хотите добавить код в функцию.

// Function that takes a currency in capital letters and returns 
function getCurrencyRates(currency, cb) {
  const currencyString = currency.toUpperCase();
  const API = "api.frankfurter.app"
  const URL = `https://${API}/latest?amount=1&from=${currencyString}&to=DKK`

  const http = new XMLHttpRequest();

  http.open("GET", URL);
  http.send();

  http.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
            cb(JSON.parse(http.responseText));        
        }
  };
}

// Call the function and pass "gbp" as currency.
// Rates will be logged in response.
getCurrencyRates('gbp', function(response) {
    console.log(response);
});
...