Как сделать чистый js-цикл обратных вызовов?

У меня есть API, из которого мне нужно запросить N страниц данных. Потому что я не хочу перегружать API, я хочу делать это последовательно и без блокировки основного потока.

Код будет примерно таким:

var res = []; // all data from api
var totalPages = 10;
var pageSize = 100;
for (let page = 0; page < totalPages; page++) {
    // load using jQuery ajax request
    $.get('api.php', { page: page, page_size: pageSize }, function(result) {
        res.push(...result); // add data to resulting array
    });
}

Но у этого подхода есть несколько проблем:

  1. Поскольку он асинхронный, он просто будет выполнять все запросы параллельно, в результате перегружая API. Мне нужно, чтобы они по-прежнему работали асинхронно, но каждый должен запускаться только после завершения предыдущего.
  2. Поскольку все вызовы асинхронные, к концу цикла у нас все равно не будет запрошенных данных — они будут загружаться в фоновом режиме. Нам нужно каким-то образом дождаться выполнения всех обратных вызовов, прежде чем возвращать res в какой-то другой код, который в этом нуждается.
  3. Невозможно заставить каждый обратный вызов передать свой результат следующему обратному вызову, и это единственный способ остановить загрузку, когда какой-либо обратный вызов получает от сервера запрос «остановить загрузку»/«нет больше данных».

Есть ли способ исправить эти проблемы без использования каких-то сторонних библиотек или промисов? Просто старый ванильный javascript. Извините, если что-то покажется непонятным, я не очень разбираюсь в js.

Реализовать очередь. Кроме того, промисы хороши по сравнению с обратными вызовами, и нет причин не использовать их.

Chris G 09.04.2022 18:57

Зачем вам все эти данные сразу? Вы должны реализовать пагинацию

proofzy 09.04.2022 18:59

@ChrisG, не могли бы вы опубликовать пример такой очереди? Что касается обещаний, могу ли я быть уверен, что по крайней мере у 99% пользователей есть браузеры, которые их поддерживают?

maxpovver 09.04.2022 19:00

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

maxpovver 09.04.2022 19:01

Обещает находятся простой ванильный javascript.

Bergi 09.04.2022 20:03

@Bergi per caniuse.com/async-функции кажется, что более 1% активных пользователей не поддерживают обещания, в том числе 0,45% хрома, 0,5% IE и 0,37% края.

maxpovver 09.04.2022 20:39

@maxpovver Если вы хотите использовать только функции, которые поддерживают более 1% используемых браузеров, напишите то, что вы имеете в виду, а не «ванильный javascript» (что означает просто js без библиотек). Однако вы уже используете jQuery, так что это все равно не ваниль. И jQuery приносит с собой реализацию обещаний! Это не правильный полифилл, но его все еще можно использовать. Вы определенно должны использовать обещания здесь.

Bergi 09.04.2022 23:46
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
7
22
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Здесь вы можете использовать простую рекурсию, например:

var res = []; // all data from api
var totalPages = 10;
var pageSize = 100;

const loader = page => {
    // load using jQuery ajax request
    $.get('api.php', { page: page, page_size: pageSize }, function(result) {
        res.push(...result); // add data to resulting array
        if (page < totalPages)
          loader(++page)
        else
          console.info('DONE!');
    });
}

loader(0);

Можно улучшить ответ, также показав, как это сделать с помощью обещанного get(), который затем можно использовать внутри цикла async for и awaiting запросов последовательно. Но да, это классический способ старой школы, который иногда полезен в более сложном коде, с которым промисы не справляются.

slebetman 09.04.2022 19:20

@slebetman Требование было without using promises, поэтому async/await отсутствует. Но вы можете написать свой ответ, если считаете, что он будет полезен.

syduki 09.04.2022 19:23

спасибо @syduki! это то, что мне было нужно. Было бы здорово также увидеть версию обещаний @slebetman

maxpovver 09.04.2022 19:25

Если я напишу свой собственный ответ, он просто будет включать полную копию/вставку вашего ответа в качестве первой его части. Было бы лучше просто избежать этого и добавить сюда

slebetman 09.04.2022 19:25

Другие вопросы по теме