catch error in promise with settimeout
Нужно отловить ошибку из промиса с сеттаймаутом и при этом получить id сеттаймаута что бы можно было его остановить. Код с которым я это пытаюсь сделать
const globalTimeout = async () => {
let timeoutId;
const timeoutPromise = new Promise(() => {
timeoutId = setTimeout(() => {
throw new Error('Request timed out');
}, 4000);
});
return {
timeoutPromise,
timeoutId,
};
};
async function loop() {
const { timeoutPromise, timeoutId } = globalTimeout();
await timeoutPromise.catch(err => { throw err;});
}
(async() => {
try {
await loop();
} catch (error) {
console.log('Error:', error);
}
})();
Ответы (2 шт):
Я обычно не использую try{}catch(){} в твоём кейсе, самостоятельно запрашивать еррор - ну такое ?
у setTimeout задаешь количество секундочек - отложенных на выполнение реквеста
С этим способом тебе не нужно будет получать ид таймаута и тд
// true = data from the request
// false = timeout "error"
const fast_fetch = false;
const fetch = async()=>{
// fetch placeholder
return await new Promise((done)=>setTimeout(()=>done('da'), fast_fetch ? 100 : 300));
};
const loopa = async()=>{
return await new Promise((done)=>{
let tookLong = true;
fetch('url').then((r)=>{
tookLong = false;
done({ok: true, data: r});
}).catch((e)=>{
done({ok: false, data: e});
});
setTimeout(()=>{
if(!tookLong)return false;
done({ok: false, data: 'Request timed out'});
}, 200);
});
};
(async()=>{
const response = await loopa();
// if(!response?.ok)throw new Error(response.data);
console.log('done', response);
})();
Ожидание выполнения какой-либо функции в течение отрезка времени возможно только если эта функция возвращает промис (за исключением случаев когда функция сама управляет прерыванием своего выполнения по внешнему значению) - потому что асинхронные очереди в цикле событий выполняются после синхронного кода итерации.
Естественно, и синхронный код функции промиса всегда выполняется полностью (если не добавлять в него выход по условию какого-то внешнего состояния). В общем, невозможно "снаружи" прервать уже выполняющийся код промиса: мы можем лишь выбирать, нужен ли нам его результат. Здесь выбор делается в зависимости от времени выполнения.
Проще говоря, принцип такой: мы помещаем в асинхронную очередь два промиса (один с полезным кодом; другой с отклонением по таймауту), и try..catch срабатывает по-разному в зависимости от того какой из этих промисов исполнится раньше. Пример ниже - показывает как можно объединить это в один промис:
const globalTimeout = (callback, delay = 4e3) => {
let timeoutId;
const promise = new Promise(async (resolve, reject) => {
timeoutId = setTimeout(() => {
reject(new Error('Request timed out')); // отклоняем, по таймауту, в этом случае `resolve` не имеет эффекта
}, delay);
const result = await callback(); // ожидаем выполнения асинхронного коллбэка...
clearTimeout(timeoutId);
resolve(result); // ...и резолвим результат
});
return { promise, timeoutId };
};
function loop() {
// какие-то действия... (код этой функции - имитация)
return new Promise(resolve => {
const isLongExecution = Math.random() < 0.5;
setTimeout(
() => resolve('Hello Stack Overflow!'),
isLongExecution ? 5e3 : 0
);
});
}
(async () => {
try {
const { promise } = globalTimeout(loop);
console.log(await promise);
} catch (err) {
console.log('Error:', err.message);
}
})();
В примере сценарий выполнения loop выбирается случайным образом (иногда быстрое, а иногда долгое - во втором случае промис таймаута исполняется раньше).
Конечно же, при "внешней" отмене таймаута через clearTimeout, его промис останется незавершенным (навечно в состоянии pending).
// Не вижу тут причин возвращать значение timeoutId, т.к. логичнее сразу снимать таймаут если коллбэк "успел"... но на всякий случай оставил это значение в возвращаемом объекте.