Асинхронный вызов функций при определенном условии в разных компонентах
Ситуация: есть экспортируемая функция, которая вызывается в разных компонентах проекта, чтобы отправить запрос на сервер с помощью fetch. Она подставляет внутри себя токен и проверку на то, что токен не просрочен, а потом делает запрос к серверу и ожидает ответ.
При заходе на сайт друг за другом все нужные запросы, допустим, 5 штук, проходящие через эту функцию, а потом идет ожидание ответа с сервера и последующая его обработка. Тут всё хорошо. Но допустим, токен оказался просроченным, и это определилось сразу после первого вызова данной функции.
Я начал отправлять внутри функции запрос к серверу для обновления токена, а значит, мне нужно временно ограничить вызов этой же функции в других компонентах, и после ответа с сервера продолжить их выполнение.
Примерный вид реализации основной функции:
const fetchAuth = async (url, n) => { //функция для запросов к API
console.log(`fetchAuth function, time = ${time}`, n)
if (time < 400) {
await updTime();
}
const fetcher = fetch(url).then(res => {
console.log(res.status, n);
})
return fetcher(url);
}
Функция для обновления токена, после выполнения которой можно продолжить выполнение функций:
const updTime = () => { //Функция для обновления времени жизни токена
console.log(`updTime function, time = ${time}`)
fetch(apiUrl).then(res => {
time = 500;
console.log(`time changed to ${time}`);
})
}
Вызываются таким образом, но в разных компонентах:
fetchAuth(apiUrl, 1).then(res => { //Допустим, вызов в первом компоненте
console.log({res}, 1);
});
fetchAuth(apiUrl, 2).then(res => { //Допустим, вызов во втором компоненте
console.log({res}, 2);
});
Полный код: https://codepen.io/kibnerk/pen/wvMKBYz
И получается, что обновление времени-токена происходит при каждом вызове.
Каким образом можно реализовать некий таймаут для выполнения последующих функций, если при вызове первой обнаружилось, что необходимое условие не соблюдается, и нужно дождаться ответа внутренней функции?
Ответы (1 шт):
Можно замкнуть флаг текущей проверки в функции высшего порядка. В ней будет хранится Promise с резолвом токена. Если Promise'a нет и токен валидный, по сразу дергаем mainFetch. Если Promise'a нет и токен не валидный, создаем Promise с ожиданием ответа апдейта токена и mainFetch будет резолвится в then. Если Promise создан, функция mainFetch будет выполнена в then этого самого токен резолвер Promise.
let time = 300;
const updateTime = () => {
console.log(`updateTime function, time = ${time}`)
return fetch(apiUrl)
.then(res => {
time = 500;
console.log(`time changed to ${time}`);
})
});
}
const fetchAuth = (() => {
let tokenUpdatePromise = null;
return (url, n) => {
console.log(`fetchAuth function, time = ${time}`, n)
if (time < 400 && !tokenUpdatePromise) {
tokenUpdatePromise = updateTime();
}
return (tokenUpdatePromise || Promise.resolve())
.then(() => fetch(url))
.then((res) => console.log(res.status, n))
.finally(() => tokenUpdatePromise = null)
}
})();