Това е 5-та част от поредица от есета. Прочетете Част 4 тук: Нашето първо AJAX обаждане XMLHttpRequest

Така че в последната статия направихме просто AJAX извикване, за да извлечем данни от API на дадена държава. Създадохме функция за това. И тъй като извикваме функцията няколко пъти, няколко AJAX извиквания са направени едновременно. Те основно вървяха паралелно и ние не можехме да контролираме кой ще завърши първи, помните ли това?

В тази статия обаче нека създадем поредица от AJAX извиквания, така че второто да се изпълнява само след като първото приключи.

Ето какво ще направим...

В данните за държавите тук има собственост на граничещите държави.

Виждате ли, този тук има кодовете MMR и IND — това е, защото тези 2 граничат с Бангладеш. Това, което ще направим сега, е след завършване на първото AJAX извикване, ще получим тази граница и след това въз основа на кода(овете) ще изобразим и съседните държави освен оригиналната държава. И така в този случай второто AJAX повикване наистина зависи от първото, защото данните за съседните държави, разбира се, са резултат от първото повикване. Без първото обаждане дори нямаше да знаем кои данни да извлечем при второто обаждане. Следователно това, което трябва да внедрим, е последователност от AJAX повиквания.

Преработих вчерашния код, така че нашият код и функции да са организирани, по-чисти и лесни за четене.

Запазих HTML съдържанието, което се показва на нашата уеб страница в резултат на извикванията на AJAX, в собствената му функция, нареченаrenderCountry().

Ако разгледате внимателно кода, ще разберете какво се случва тук, защото е прост и ясен.

[необработен код, предоставен в края на статията]

Тук основно изпращаме заявката, след което заявката извлича данните във фонов режим. След като това стане, то ще пропусне събитието за зареждане. Слушателят на събития чака това събитие и веднага щом данните пристигнат, функцията за обратно извикване в него ще бъде извикана.

Във вчерашния пример направихме само една заявка и получихме един отговор. Ето как ще работи, когато всичко, което правим, е да имаме достъп до API. Ако обаче имаме достъп до УЕБ СТРАНИЦА, тогава ще има много повече заявки и отговори. И това е така, защото когато направим първата заявка, всичко, което получаваме обратно, е само първоначалния HTML файл. След това този HTML файл ще бъде сканиран от браузъра за всички активи, от които се нуждае, за да изгради цялата уеб страница като JavaScript, CSS файлове, файлове с изображения или други активи. И тогава за всеки различен файл ще има нова HTTP заявка, направена към сървъра. Когато всички файлове най-накрая са пристигнали, тогава уеб страницата може да бъде изобразена в браузъра, в съответствие със спецификациите за HTML, CSS и JavaScript.

Сега, ако искаме тези заявки да бъдат направени в конкретен предварително дефиниран ред, тогава ще трябва основно да ланцуговаме заявките. Което означава да направите втората заявка едва след като първата заявка приключи. Това води до нещо, наречено АДЪТ НА ОБРАТНОТО ПОВИКВАНЕ!

Днес това, което току-що направихме, беше направихме AJAX повикване за държава, след което след като получим данните, извикваме съседа на тази държава:

getCountryAndNeighbour('германия');

Така че тук прикачихме първата функция за обратно извикване. И тогава вътре в него имаме още един. Така че имаме вложени обратни извиквания. Но ако трябва да намерим съседа на съседите, тогава трябва да добавим обратно извикване вътре в обратно извикване, така нататък... това води до нещо, наречено CALLBACK HELL.

Адът на обратното извикване е, когато имаме много вложени обратни извиквания, за да изпълним последователно асинхронни задачи. И всъщност това се случва за всички асинхронни задачи, които се обработват от обратни извиквания (например вложена функция setTimeout), а не само AJAX извиквания.

Сега, проблемът с ада за обратно извикване е, че прави нашия код да изглежда много разхвърлян. Но още по-важното е, че това прави нашия код по-труден за поддръжка и много труден за разбиране, сега колкото по-трудно е да разберем кода и да разсъждаваме върху него, толкова по-трудно ще бъде добавянето на нови функции.

От ES6 всъщност има начин за избягване на ада на обратното извикване чрез използване на нещо, наречено PROMISES.

ajax-с-обратно извикване.js

const getCountryAndNeighbor = function (country) {
    //AJAX call for country
    const request = new XMLHttpRequest();
    request.open('GET', `https://restcountries.com/v3.1/name/${country}`);
  
    request.send();
  
    request.addEventListener('load', function () {
      const [data] = JSON.parse(this.responseText);
      console.log(data);
  
      // Render country:
      renderCountry(data);
  
      //Get country neighbour
      let neighbour = 0;
      if (!data.borders) {
        return; // If no neighbour then simply return
      } else {
        for (let neighbour of data.borders) {
          //AJAX call for neighbour
          const requestNeighbour = new XMLHttpRequest();
          requestNeighbour.open(
            'GET',
            `https://restcountries.com/v3.1/alpha/${neighbour}` //alpha used in link instead of name bcz neighbour is the code
          );
          requestNeighbour.send();
  
          requestNeighbour.addEventListener('load', function () {
            const [dataNeighbour] = JSON.parse(this.responseText);
            // console.log(dataNeighbour);
            renderCountry(dataNeighbour);
          });
        }
      }
    });
  };
  
  const renderCountry = data => {
    const lang = Object.values(data.languages).join(',');
        const currencies = Object.values(data.currencies).map((currency) => currency.name).join(',');
        const borders = Object.values(data.borders).map(border => border).join(',' + ' ');
        
        const html = `
       
        <table>
<tr>
                <td>Country Flag:</td>
                <td><img src="${data.flags.png}"/></td>
            </tr>
            <tr>
                <td>Country Name:</td>
                <td>${data.name.common}</td>
            </tr>
            <tr>
                <td>Capital city:</td>
                <td>${data.capital}</td>
            </tr>
            <tr>
                <td>Region:</td>
                <td>${data.region}</td>
            </tr>
            <tr>
                <td>Continent:</td>
                <td>${data.continents}</td>
            </tr>
            <tr>
                <td>Borders:</td>
                <td>${borders}</td>
            </tr>
            <tr>
                <td>Population:</td>
                <td>${data.population} ~ ${+(data.population / 1000000).toFixed(1)} M</td>
            </tr>
            <tr>
                <td>Language: </td>
                <td> ${lang} </td>
            </tr>
            <tr>
                <td>Currency: </td>
                <td> ${currencies} </td>
            </tr>
        </table>
        <br/>
        `;
        const divEl = document.createElement('div');
        divEl.innerHTML = html;
        
        document.body.appendChild(divEl);
      
  };
// getCountryAndNeighbor('bangladesh');
// getCountryAndNeighbor('canada');
getCountryAndNeighbor('germany');

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Asynchronous JavaScript ~ AJAX</title>
  </head>
  <body>
    <script defer src="ajax.js"></script>
    <script defer src="ajax-with-callback.js"></script>
  </body>
</html>

Ако искате да четете моите статии … ♥️ последвайте ме и се абонирайте за моя имейл списък на носител: https://medium.com/@ruckaiya.awf5, за да бъдете уведомени за публикуването на следващата статия.