Библиотека асинхронных запросов для react?

Если ajax запрос данных с сервера может быть длительным (2 и более секунд), в современных фреймворках типа react без проблем можно отображать progressbar, значок загрузки и т.п. Но в это время пользователь имеет право работать с приложением дальше, нажимать различные кнопки, т.е. запускать другие процессы загрузки данных и т.п. Так вот вопрос - существует ли на данный момент библиотека, которая способна разрулить такой хаос в действиях пользователя?
Пример некорректных возможных обработок:
1) Клиент выбрал фильтры в форме поиска, нажал кнопку, данные грузятся... далее юзер выбрал другие параметры фильтров, снова нажал кнопку - в результате второй запрос теоретически может отработать быстрее первого, затем придут данные от первого запроса, в результате - параметры заданных юзером фильтров будут от второго запроса, а отображаемый результат - от первого.
2) Повторная отсылка данных формы - тут конечно есть стандартный метод блокирования кнопки от нажатия, но желательно бы это перенести на функциональность быблиотеки.

Вот примерное тз для такой библиотеки:
Типы процессов:
1) Получение доп данных (например полный текст статьи в блоге)
- Если target компонент скрывается (переходим на другую вкладку, закрыли компонент, и т.п.) - то отменяем процесс.
- Если повторный запрос тех же самых данных - игнорируем такой запрос.
- Отменить загрузку можем и по нажатию кнопки.
2) Получение дынных формы с заданными фильтрами на входе (поиск по параметрам например)
- Во время загрузки фильтры показываем как их выбрал юзер.
- Если target компонент скрывается, то отменяем процесс.
- Если задали другие фильтры на входе, то отменяем прежний процесс и создаем новый.
- Если отменили загрузку, то возвращаем фильтры в исходное состояние.

+ данные могут поступать по websocket

В общем случае это получается некий конечный автомат с правилами на любой штатный/внештатный случай. Есть ли сейчас что-то такое готовое?
  • Вопрос задан
  • 1351 просмотр
Пригласить эксперта
Ответы на вопрос 4
Да, такая библиотека есть. Проблема в том, что в JS нативные промисы (Promise) нельзя отменить (not cancelable)... но при этом - у нас есть генераторы, которые вполне себе позволяют имитировать отмену выполнения какой-либо функции, скажем, в середине.

Для того, чтобы все заработало - вам нужно использовать связку из любой понравившейся библиотеки для непосредственно запросов (я предпочитаю isomorphic-fetch), затем взять redux и middleware для него (редакса) - redux-saga.

Если вы не знакомы с экосистемой редакса или первый раз слышите про redux-saga - прочтите документацию, посмотрите уроки. Если вкратце - библиотека построена на генераторах. Функция-генератор возвращает итератор и ее выполнение прекращается каждый раз, когда мы возвращаем итератору новое значение (yield)

Ниже продемонстрирую как это примерно работает:

function* myCancelableAction(someData) {
  // вернет итератору промис и приостановит работу функции до следующего вызова next
  // в нашем случае - функция продолжит выполнение, когда придет ответ сервера
  const response = yield doAjaxRequest(someData) 
  yield dispatchSuccessAction(response)
}

const action = myCancelableAction();
const promise = action.next().value // fetch promise

promise.then(response => {
  // если новых запросов не поступило
  if(!newRequestIsComing) {
    // мы можем передать значение в нашу функцию (через next)
    console.log(action.next(response).value); // dispatched action
  }
})


Таким образом, после того, как функция вернула значение первый раз, применительно к теме поста это будет "сделай AJAX-запрос", мы можем не выполнять ее дальше (если захотим). Отменить ajax запрос в этом случае не получится, но мы можем просто не учитывать его результаты (не диспатчить success-экшен, например).

UPD1 обновил пример кода
Ответ написан
Комментировать
dpigo
@dpigo
Front-end developer
Посмотрите в сторону RxJS
Ответ написан
@LiguidCool
Ну так это издержки асинхронности, за которые так любят, и так ненавидят JS.
Думаю для того же React или Angular это все изрежки программиста, писавшего код. По большому счету нельзя блокировать что-то на время выполнения асинхрона. Например вы сделали запрос данных и на это время через state (я про React) заблокировали кнопку ... А потом ваш AJAX взял и не вернулся (ну магия какая-то). И абзац - жми F5.
И кстати, может если сервер так долго отдаёт данные, то ... Хм пусть отдает все сразу, а фильтрует пусть фронтэнд. Попробуйте, может это ваше решение.
Ответ написан
maxfarseer
@maxfarseer
https://maxpfrontend.ru, обучаю реакту и компании
Тоже столкнулся с подобной проблемой, опишу как это в черновике выглядит у себя, но в целом пока красиво решено не было:

Есть проект, на бэкэнде elixir+phoenix. Мне в каждом сообщении приходит ref + автоинкреметный id. Следовательно, когда я делаю первый запрос и данные идут долго, а потом второй запрос и данные приходят быстрее, то ref будет больше и я просто в редьюсере игнорирую старый ответ (в стиле, action.ref < state.ref => верни текущий стэйт).

P.S. если используете сокеты, как вы "замедляете" получение ответа? Мне пришлось попросить "бэкэнд" отвечать медленнее, для тестирования этой проблемы. Так как в chrome devtools в нетворке "замедление" не работало для запросов по сокету.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы