Skip to content

Instantly share code, notes, and snippets.

@ipetropolsky
Created May 14, 2019 14:09
Show Gist options
  • Save ipetropolsky/d6da3230551dacd56efde6b51003c74c to your computer and use it in GitHub Desktop.
Save ipetropolsky/d6da3230551dacd56efde6b51003c74c to your computer and use it in GitHub Desktop.
Fetcher with canceling requests by groups and tags
import axios, { CancelToken, isCancel } from 'axios';
const instance = axios.create({
withCredentials: true,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
});
let nextRequestId = 0;
function shouldCancel(oldRequest, newRequest) {
return oldRequest.cancelTags.some((tag) => newRequest.cancelTags.includes(tag));
}
function CancelGroup() {
let requests = [];
return {
add(newRequest) {
requests = requests.filter((oldRequest) => {
if (shouldCancel(oldRequest, newRequest)) {
oldRequest.cancel();
return false;
}
return true;
});
requests.push(newRequest);
},
remove(requestId) {
requests = requests.filter((request) => {
return request.requestId !== requestId;
});
},
filter(filter) {
requests = requests.filter(filter);
},
};
}
/**
* Хранилище отменяемых запросов.
*
* Если делается запрос с `cancelGroup` и `cancelTags`, отменяются запросы
* с такой же группой и совпадением одного из тегов. Нужно для тонкой настройки
* отмены, например, когда запрос на редактирование отменяет только другие запросы
* на редактирование, а запрос на удаление отменяет и редактирование, и удаление.
* Группа ограничивает область отмены, например, если редактирование одного ID
* не должно отменять редактирование другого, делаются запросы с разными группами.
*
* @type {{ cancelGroup: [ { requestId, cancelTags[], cancel() } ] }}
*/
const cancelGroups = {};
instance.interceptors.request.use(
(config) => {
const requestId = nextRequestId;
const { cancelGroup, cancelTags } = config;
if (cancelGroup && cancelTags && cancelTags.length) {
const source = CancelToken.source();
config.cancelToken = source.token;
cancelGroups[cancelGroup] = cancelGroups[cancelGroup] || new CancelGroup();
cancelGroups[cancelGroup].add({ requestId, cancelTags, cancel: source.cancel });
}
config.requestId = requestId;
nextRequestId += 1;
return config;
},
(error) => {
return Promise.reject(error);
}
);
instance.interceptors.response.use(
(response) => {
const { requestId, cancelGroup } = response.config;
if (cancelGroup && cancelGroups[cancelGroup]) {
cancelGroups[cancelGroup].remove(requestId);
}
return response;
},
(error) => {
error.isCancel = isCancel(error);
return Promise.reject(error);
}
);
export default instance;
import fetcher from './fetcher';
// ...
// save
fetcher.post('/url', data, {
cancelGroup: internalId,
cancelTags: ['automoderation', 'save'],
});
// delete
fetcher.delete('/url', {
cancelGroup: internalId,
cancelTags: ['save', 'automoderation', 'delete'],
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment