Выполнить функцию после завершения всех XMLHttpRequests

#javascript #node.js #typescript #dom #web-analytics

#javascript #node.js #typescript #dom #веб-аналитика

Вопрос:

КРАТКОЕ

У меня есть веб-сайт, который получает данные из API. Таким образом, он отправляет некоторые запросы post и get на сервер после открытия веб-сайта. Давайте предположим, что она выполняет 5 разных XMLHttpRequests сразу после загрузки страницы, но мы не можем точно знать, сколько времени занимает каждый вызов от начала до конца.

НАПРИМЕР

Выполнение вызова одной конечной точки занимает 2 секунды, а другой — 1 секунду. Таким образом, это означает, что через 2 секунды оба вызова считаются завершенными.

TO-DO

Я хочу выполнить функцию после того, как все XMLHttpRequests завершены, потому что я использую window.performance.getEntries() для извлечения всех запросов, инициированных веб-страницей, и отправки их на мой сервер, поскольку я выполняю проект веб-аналитики, в котором мне нужно получить доступ к времени, затраченному на каждый сетевой запрос, и преобразовать данные в диаграмму.

ДОПОЛНИТЕЛЬНЫЙ ВОПРОС ИЛИ ПОДСКАЗКА

Есть ли какое-либо событие, которое можно прикрепить к окну, как показано ниже, для прослушивания всех сетевых вызовов и выполнения моего фрагмента кода, когда все будут завершены.

       window.addEventListener("load", function (event) {
       //execute some code here
      }
  

В событии загрузки я не могу захватить все запросы с помощью performance.getEntries(), потому что загрузка запускается до завершения вызовов ajax.

Как показано выше, я спрашиваю. Есть ли какой-либо трюк или какое-либо событие или что-либо в JavaScript, с помощью которого мы можем дождаться завершения всех XMLHTTPREQUESTS, а затем выполнить некоторый код.

Ответ №1:

РАБОЧЕЕ РЕШЕНИЕ

Мы можем отслеживать вызовы AJAX браузера, используя приведенный ниже код :

   const ajaxCallStatus = () => {
   window.ajaxCalls = 0; // initial ajax calls
   window.ajaxEndpoints = []; // keeping track of all ajax call urls (endpoints) 
   const origOpen = XMLHttpRequest.prototype.open;
   XMLHttpRequest.prototype.open = function() {
   window.ajaxCalls  ;
   this.addEventListener('load', (event) => {
    if (!window.ajaxEndpoints.includes(event['currentTarget'].responseURL)) {
      window.ajaxEndpoints.push(event['currentTarget'].responseURL);
    }
    window.ajaxCalls--;
    switch (window.ajaxCalls) {
    case 0: // when ajax calls finish this runs
      addData(window.ajaxEndpoints);
    break;
    }
     });
    origOpen.apply(this, arguments);
    }
   }
  

ФУНКЦИЯ ДОБАВЛЕНИЯ ДАННЫХ — Используется для отправки данных в некоторый серверный сервер.

 function addData(arr, origOpen) { 
   XMLHttpRequest.prototype.open = origOpen;
   axios.post('url', data)
  .then((res) => console.log(res))
  .catch((err) => console.log(err));
}
  

Ответ №2:

Я бы посоветовал вам обернуть ваши запросы в promises, а затем использовать Promise.all(...) вот так:

 const makeRequest = () => {
    return new Promise((resolve, reject) => {
        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function() {
            if (this.readyState == 4 amp;amp; this.status == 200) {
                resolve(xhttp.responseText); // On success, resolve the promise
            } else {
                reject(); // On failure, reject it
            }
        };
        xhttp.open("GET", "filename", true); // Needs to be set to your needs. This is just an example
        xhttp.send();
    });
}

// This waits until all promises are resolved
const [result1, result2] = await Promise.all(makeRequest(), makeRequest());

// do stuff here with your results
console.log(result1);
console.log(result2);
  

PS: Базовый пример Ajax взят отсюда, но просто замените его на свой и создайте параметры или аналогичные для выполнения запросов, которые вам действительно нужны

или

Вы могли бы использовать библиотеку, подобную Axios, для запросов Ajax, которая уже возвращает обещания по умолчанию. Проверьте это здесь:https://github.com/axios/axios

Комментарии:

1. Давайте предположим, что я поставщик программных услуг веб-аналитики, и я не могу сказать своему пользователю, чтобы он преобразовывал сетевые вызовы в Promise.all . Вместо этого я хочу предоставить тег script, который можно добавить в их HTML-файл и автоматически загрузить на веб-страницу, и в этом теге script у меня настроены все прослушиватели событий. Например, DOMContentLoaded и т.д. Итак, есть ли какое-либо событие или способ, с помощью которого мы можем обработать мою потребность? Необходимость прослушивания всех запросов xmlhttp, выполненных или нет

2. Нет надежного способа сделать это, потому что XMLHttpRequests по определению асинхронны. Вы не можете ждать начальной загрузки, потому что всегда могут быть новые запросы или что-то в этом роде. Если их можно как-то идентифицировать, это может быть другая история, но только из того, что вы мне рассказываете, это кажется невозможным. Возможно, вы захотите проверить это: medium.com/@gilfink /… . Возможно, это соответствует вашим потребностям. Прокрутка вниз до раздела xmlhttp @basitmir