Обычно я делаю это в самом обещании и избегаю накладных расходов двух отдельных обещаний.
function getResponse(...params) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error("Timed out to get response"))
// some code to abort request
}, 3000)
// some code which resolves promise
})
}
Полезно, обещания игнорируют более поздние решения и / или отклонения после того, как вы решите это в первый раз. Если вы можете программно прервать его, не применяя логику разрешения, это становится намного проще, но даже если вы не можете, вы всегда можете задать логическое значение, чтобы заблокировать будущие запросы. Это также облегчает добавление поддержки отмены позже, что также полезно. Если вам нужно также отключить тайм-аут (если вы делаете какую-то мутацию DOM или чтение файла - вам редко нужно это делать), вы можете сделать что-то вроде этого:
function getResponse(...params) {
return new Promise((reallyResolve, reallyReject) => {
let resolved = false
let id = setTimeout(() => {
reject(new Error("Timed out to get response"))
abort()
}, 3000)
// I'll use these instead of the `resolve`/`reject` callbacks directly.
function resolve(value) {
if (resolved) return
resolved = true
clearTimeout(id)
reallyResolve(value)
}
function reject(value) {
if (resolved) return
resolved = true
clearTimeout(id)
reallyReject(value)
}
function abort() {
// some code to abort request
}
// some code which resolves promise
})
}
Это позволяет мне не беспокоиться об организации всего, но все равно работает.
Если вам не нужна логика прерывания (она действительно нужна только для сетевых запросов и т. П.), Это становится намного проще:
function timeout(ms) {
return new Promise((_, reject) => {
setTimeout(() => reject(new Error("Timed out")), ms)
})
}
function getResponse(...params) {
return Promise.race([
timeout(3000),
doSomethingAsync(),
])
}