Как отменить fetch?

413
17 июня 2017, 14:53

на форме фильтр + грид

данные с бэка забираю через fetch

полученными данными обновляется грид

запрос довольно тяжелый / долгий

проблема возникает когда пользователь генерит новый запрос до завершения предыдущего

контент в гриде обновляется несколько раз

можно как то прервать / отказаться от "устаревшего" запроса?

P.S. обертывание fetch в clearTimeout / setTimeout в данной ситуации не спасает

P.S.S. или както проверять является ли полученный данные результатом последнего promis'а?

UPDATE

страница на ReactJS

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

ситуация в том, что нет кнопки "НАЙТИ", запрос генерится при каждом "чихе" в фильтре

фильтр огромный из 10ков полей и выпадающих списков

дисейблить его при каждом запросе не получится по идеалогическим соображениям клиента

вижу единственный вариант это отказываться или игнорировать устаревшие запросы

но хотел поискать BEST PRACTICES

UPDATE2

class View extends Component {
    ...
    updateItems(data) {
        self.state.timeoutItems && clearTimeout(self.state.timeoutItems);
        self.state.timeoutItems = setTimeout(() => {
            self.props.onGetItems(self.calcParams());
        }, config.timeoutItems );
    }  
}

export default connect(
    state => ({
        items: state.items
    }),
    dispatch => ({
        onGetItems: (o) => {
            dispatch(getItems(o));
        }
    })
)(View);

...

export const getItems = (o = {}) => dispatch => {
    ...
    fetch(url, {  
        method: 'GET',              
        headers: {
            "Content-type": "application/json",
            "Accept": "application/json"
        },  
    })
    .then( (response) => response.json() )
    .then((data) => {
        ==>> (1) <<==
        dispatch({ type: 'FETCH_ITEMS_SUCCESS', data: data });
    })  
    .catch((error) => {
        console.log('Request failed', error);  
    });
}

можно ли в точке (1) определить к какому promise относится полученный результат?

Answer 1

На текущее время нативно отменить fetch нельзя, это потому что он использует механизм Promise-ов, в которых тоже нет механизма прерывания. Поэтому приходится ухитряться и писать костыли

Есть библиотека axios, тоже использует Promise, правда работает вроде все еще на стандартном XMLHttpRequest, но возможность отмены там есть:

var CancelToken = axios.CancelToken;
var source = CancelToken.source();
axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function(thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // handle error
  }
});
// cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.');

Если хотите использовать нативный fetch придется пока писать свою реализацию отмены запроса (да и то, это не будет настоящей отменой запроса, потому что ответ все равно придет, просто вы его проигнорируете)

UPD

Дискасс на эту тему

Answer 2

Способа отменить fetch нет и вроде как не предвидится.

Выбрать наиболее новый и отрисовать именно его можно как-то так:

let counter = 0; // Флаг итератора количества запросов 
 
function buildRequest(){ 
  console.info(`Запрос #${counter + 1} послан`); 
  makeRequest(++counter); // Новый запрос получает более большое число 
} 
 
function makeRequest(num){ 
  setTimeout(_ => { 
    if(counter > num){ // Если итератор больше текущего числа, значит был запрос позже, выходим 
      console.info(`Запрос #${num} отменён, есть запросы позже`); 
      return; 
    } 
     
    // Иначе рисуем ответ 
    console.info(`Запрос #${num} начинает отрисовку`); 
  }, 1000); 
} 
 
buildRequest(); 
setTimeout(_ => buildRequest(), 500); 
setTimeout(_ => buildRequest(), 1000);

Но сервер всё равно будет в поте процессора трудится.

Иначе либо ставьте запросы в очередь, либо сделайте заблокируйте фильтры на момент запроса.

READ ALSO
Загрузка google maps при скролле

Загрузка google maps при скролле

Как сделать так, чтобы гугл карты загружались на сайт после того, как пользователь совершил какие-либо действия(например, проскроллил страницу)...

212
console.log(&#39;hello&#39;,)

console.log('hello',)

Не знал как назвать, кто придумает по умнее, буду признателенПроблема в том, что PhpStorm не подчеркнул и я упустил из виду:

226