Promise.race与延迟实现请求超时控制 - 解析azu/promises-book高级技巧
promises-book JavaScript Promiseの本 项目地址: https://gitcode.com/gh_mirrors/pr/promises-book
前言
在现代前端开发中,异步操作管理是核心挑战之一。Promise作为ES6引入的异步编程解决方案,为我们提供了更优雅的流程控制方式。本文将深入探讨如何利用Promise.race结合延迟函数实现请求超时控制,这是azu/promises-book项目中介绍的高级Promise技巧。
基础概念回顾
Promise.race简介
Promise.race是Promise的静态方法,它接收一个Promise数组作为参数,返回一个新的Promise。这个新Promise的状态将由数组中第一个状态改变的Promise决定。
const promise1 = new Promise((resolve) => setTimeout(resolve, 500, 'one'));
const promise2 = new Promise((resolve) => setTimeout(resolve, 100, 'two'));
Promise.race([promise1, promise2]).then((value) => {
console.log(value); // 输出 'two'
});
实现延迟Promise
要实现超时控制,首先需要创建一个能在指定时间后resolve的Promise:
function delayPromise(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
// 使用示例
delayPromise(1000).then(() => {
console.log('1秒后执行');
});
实现请求超时控制
基础超时实现
结合Promise.race和delayPromise,我们可以实现基本的超时控制:
function timeoutPromise(promise, ms) {
const timeout = delayPromise(ms).then(() => {
throw new Error('操作超时');
});
return Promise.race([promise, timeout]);
}
// 使用示例
const taskPromise = new Promise((resolve) => {
setTimeout(() => resolve('任务完成'), 2000);
});
timeoutPromise(taskPromise, 1500)
.then(console.log) // 如果1.5秒内完成
.catch(console.error); // 如果超时
自定义超时错误类型
为了更好地区分普通错误和超时错误,我们可以创建自定义错误类型:
function TimeoutError(message) {
this.name = 'TimeoutError';
this.message = message || '操作超时';
this.stack = (new Error()).stack;
}
TimeoutError.prototype = Object.create(Error.prototype);
TimeoutError.prototype.constructor = TimeoutError;
// 使用示例
throw new TimeoutError('自定义超时消息');
XMLHttpRequest的超时控制
可取消的XHR封装
要实现XHR的超时控制,首先需要封装一个可取消的XHR Promise:
function cancelableXHR(url) {
const req = new XMLHttpRequest();
let abort = null;
const promise = new Promise((resolve, reject) => {
req.open('GET', url, true);
req.onload = () => {
if (req.status === 200) {
resolve(req.responseText);
} else {
reject(new Error(req.statusText));
}
};
req.onerror = () => reject(new Error(req.statusText));
req.onabort = () => reject(new TimeoutError('请求被中止'));
req.send();
abort = () => req.abort();
});
return {
promise,
abort
};
}
完整超时控制实现
结合上述所有组件,完整的XHR超时控制实现如下:
function fetchWithTimeout(url, timeout) {
const { promise, abort } = cancelableXHR(url);
const timeoutPromise = delayPromise(timeout).then(() => {
throw new TimeoutError('请求超时');
});
return {
promise: Promise.race([promise, timeoutPromise]),
abort
};
}
// 使用示例
const { promise, abort } = fetchWithTimeout('https://api.example.com/data', 5000);
promise
.then(data => console.log('获取数据:', data))
.catch(error => {
if (error instanceof TimeoutError) {
console.error('请求超时,已取消');
abort(); // 显式取消请求
} else {
console.error('其他错误:', error);
}
});
模块化设计建议
为了更好的代码组织和复用,建议将相关功能模块化:
// cancelableXHR.js
module.exports = {
createXHRPromise(url) {
// 返回XHR Promise实现
},
abortPromise(promise) {
// 取消对应的XHR请求
}
};
// timeout.js
module.exports = {
delayPromise(ms) {
// 延迟Promise实现
},
timeoutPromise(promise, ms) {
// 超时控制实现
}
};
现代替代方案:AbortController
随着Fetch API的普及,现在可以使用更现代的AbortController来实现请求取消:
const controller = new AbortController();
const signal = controller.signal;
fetch('https://api.example.com/data', { signal })
.then(response => response.json())
.catch(error => {
if (error.name === 'AbortError') {
console.log('请求被取消');
}
});
// 取消请求
controller.abort();
总结
本文深入探讨了如何利用Promise.race和延迟函数实现请求超时控制,主要内容包括:
- 使用delayPromise创建延迟解决的Promise
- 结合Promise.race实现超时控制逻辑
- 创建自定义TimeoutError以便区分错误类型
- 封装可取消的XHR请求
- 模块化设计的最佳实践
- 现代Fetch API的AbortController方案
Promise的强大之处在于它提供了清晰的异步流程控制能力。通过合理的功能分解和模块化设计,我们可以构建出既强大又易于维护的异步代码结构。
promises-book JavaScript Promiseの本 项目地址: https://gitcode.com/gh_mirrors/pr/promises-book
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考