Как сделать чистый 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
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Сравнение структур данных: Массивы и объекты в Javascript
Сравнение структур данных: Массивы и объекты в Javascript
Итак, вы изучили основы JavaScript и хотите перейти к изучению структур данных. Мотивация для изучения/понимания Структур данных может быть разной,...
Создание собственной системы электронной коммерции на базе Keystone.js - настройка среды и базовые модели
Создание собственной системы электронной коммерции на базе Keystone.js - настройка среды и базовые модели
Прошлая статья была первой из цикла статей о создании системы электронной коммерции с использованием Keystone.js, и она была посвящена главным образом...
Приложение для отслеживания бюджета на React js для начинающих
Приложение для отслеживания бюджета на React js для начинающих
Обучение на практике - это проверенная тема для достижения успеха в любой области. Если вы знаете контекст фразы "Практика делает человека...
Стоит ли использовать React в 2022 году?
Стоит ли использовать React в 2022 году?
В 2022 году мы все слышим о трендах фронтенда (React, Vue), но мы не знаем, почему мы должны использовать эти фреймворки, когда их использовать, а...
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.log('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

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