Promise 是 JavaScript 中一种处理异步操作的机制,它可以让我们更方便地处理异步操作,避免回调地狱等问题。在前端开发中,我们常常需要发起多个并发请求,这时候就需要解决 Promise 并发请求时的超时和取消问题。
什么是超时和取消问题
在并发请求的场景下,我们可能会遇到一些问题。例如,某个请求可能会因为网络问题或者服务器问题而一直没有响应,导致其他请求也无法继续执行。此外,如果我们需要在一定时间内获取所有请求的结果,那么如果某个请求一直没有响应,我们可能需要考虑超时的问题。另外,如果我们需要取消某个请求,也需要解决这个问题。
解决方案
超时问题
超时问题可以通过 Promise.race() 方法解决。Promise.race() 方法接收一个 Promise 数组作为参数,返回一个新的 Promise 对象。当 Promise 数组中的任意一个 Promise 对象状态改变时,返回的 Promise 对象状态也会改变。具体来说,当 Promise 数组中的某个 Promise 对象成功时,返回的 Promise 对象也会成功;当 Promise 数组中的某个 Promise 对象失败时,返回的 Promise 对象也会失败。另外,Promise.race() 方法会返回第一个状态改变的 Promise 对象的结果。
我们可以利用 Promise.race() 方法来实现超时功能。具体来说,我们可以创建一个 Promise 对象,然后使用 Promise.race() 方法将其与一个定时器 Promise 对象组合起来。如果定时器 Promise 对象先状态改变了,那么说明超时了;否则,就说明请求成功或失败了。
// www.javascriptcn.com code example
function timeoutPromise(promise, timeout) {
return Promise.race([
promise,
new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('Timeout'));
}, timeout);
})
]);
}上面的代码中,timeoutPromise() 方法接收一个 Promise 对象和一个超时时间,返回一个新的 Promise 对象。在这个方法中,我们使用 Promise.race() 方法将传入的 Promise 对象与一个定时器 Promise 对象组合起来,如果定时器 Promise 对象先状态改变了,就会返回一个超时错误。
取消问题
取消问题可以通过 AbortController 和 AbortSignal 解决。AbortController 是一个控制器,用于控制一个或多个正在进行的操作。AbortSignal 是一个信号,用于通信操作的状态。当 AbortController 调用 abort() 方法时,与该控制器关联的所有操作都会被取消,而与该控制器关联的 AbortSignal 将被激活。
我们可以在发起请求时使用 AbortController 和 AbortSignal 对象,然后在需要取消请求的时候调用 AbortController 的 abort() 方法即可。
// www.javascriptcn.com code example
function fetchWithAbort(url, options) {
const controller = new AbortController();
const signal = controller.signal;
const promise = fetch(url, { ...options, signal });
promise.abort = () => {
controller.abort();
};
return promise;
}上面的代码中,fetchWithAbort() 方法接收一个 URL 和一些配置选项,返回一个新的 Promise 对象。在这个方法中,我们创建了一个 AbortController 对象和一个 AbortSignal 对象,并将 AbortSignal 对象作为请求的 signal 参数。然后,我们将 AbortController 的 abort() 方法赋值给返回的 Promise 对象的 abort 属性,以便在需要取消请求时调用。
示例代码
// www.javascriptcn.com code example
function timeoutPromise(promise, timeout) {
return Promise.race([
promise,
new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('Timeout'));
}, timeout);
})
]);
}
function fetchWithAbort(url, options) {
const controller = new AbortController();
const signal = controller.signal;
const promise = fetch(url, { ...options, signal });
promise.abort = () => {
controller.abort();
};
return promise;
}
const promise1 = timeoutPromise(fetchWithAbort('https://jsonplaceholder.typicode.com/todos/1'), 1000);
const promise2 = timeoutPromise(fetchWithAbort('https://jsonplaceholder.typicode.com/todos/2'), 2000);
const promise3 = timeoutPromise(fetchWithAbort('https://jsonplaceholder.typicode.com/todos/3'), 3000);
Promise.all([promise1, promise2, promise3])
.then(responses => {
console.log(responses);
})
.catch(error => {
console.error(error);
});
promise2.abort();上面的代码中,我们使用 timeoutPromise() 方法和 fetchWithAbort() 方法来解决超时和取消问题。然后,我们创建了三个并发请求,并使用 Promise.all() 方法等待它们全部完成。最后,我们取消了第二个请求。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d41377a941bf71347b92fe