代码封装:超时重传方法

JS+Fetch

在 JavaScript 中,我们可以使用 fetch API 来封装一个带有超时和重试功能的请求方法。以下是一个示例代码:

封装代码

javascript 复制代码
/**
 * 带有超时和重试功能的请求方法
 * @param {string} url - 请求的URL
 * @param {Object} options - fetch的配置选项
 * @param {number} timeout - 超时时间(毫秒)
 * @param {number} maxRetries - 最大重试次数
 * @returns {Promise<Response>} - 返回fetch的响应
 */
async function fetchWithRetry(url, options = {}, timeout = 5000, maxRetries = 3) {
    let retries = 0;

    while (retries < maxRetries) {
        try {
            // 创建一个超时控制器
            const controller = new AbortController();
            const timeoutId = setTimeout(() => controller.abort(), timeout);

            // 发起请求
            const response = await fetch(url, {
                ...options,
                signal: controller.signal, // 绑定超时控制器
            });

            // 清除超时计时器
            clearTimeout(timeoutId);

            // 如果响应状态码不是2xx,抛出错误
            if (!response.ok) {
                throw new Error(`请求失败,状态码: ${response.status}`);
            }

            // 返回响应
            return response;
        } catch (error) {
            retries++;
            console.warn(`请求失败,重试次数: ${retries}, 错误: ${error.message}`);

            // 如果达到最大重试次数,抛出错误
            if (retries >= maxRetries) {
                throw new Error(`请求失败,已达到最大重试次数: ${maxRetries}`);
            }
        }
    }
}

// 使用示例
(async () => {
    try {
        const url = "https://jsonplaceholder.typicode.com/posts/1";
        const response = await fetchWithRetry(url, {}, 2000, 3); // 超时2秒,最大重试3次
        const data = await response.json();
        console.log("请求成功:", data);
    } catch (error) {
        console.error("请求最终失败:", error.message);
    }
})();

代码说明:

  1. 超时控制

    • 使用 AbortControllersetTimeout 实现请求超时功能。
    • 如果请求超时,调用 controller.abort() 中断请求。
  2. 重试机制

    • 使用 while 循环和 retries 计数器实现重试逻辑。
    • 如果请求失败(超时或响应状态码非2xx),则重试,直到达到最大重试次数。
  3. 错误处理

    • 如果请求失败,会抛出错误并重试。
    • 如果达到最大重试次数,抛出最终错误。
  4. 使用示例

    • 调用 fetchWithRetry 方法时,传入 URL、配置选项、超时时间和最大重试次数。
    • 请求成功后,返回响应数据;失败后,抛出错误。

示例输出:

  • 如果请求成功:

    css 复制代码
    请求成功: { userId: 1, id: 1, title: "...", body: "..." }
  • 如果请求失败:

    makefile 复制代码
    请求失败,重试次数: 1, 错误: Request failed, status code: 500
    请求失败,重试次数: 2, 错误: Request failed, status code: 500
    请求失败,重试次数: 3, 错误: Request failed, status code: 500
    请求最终失败: 请求失败,已达到最大重试次数: 3

注意事项:

  1. 浏览器兼容性

    • AbortControllerfetch 在现代浏览器中支持良好,但在旧版浏览器中可能需要 polyfill。
    • 如果需要兼容旧版浏览器,可以使用 axios 库替代 fetch
  2. 重试间隔

    • 当前代码是立即重试。如果需要增加重试间隔,可以在 catch 块中添加 await new Promise(resolve => setTimeout(resolve, delay))
  3. 性能优化

    • 如果请求失败的原因是服务器过载,建议增加指数退避策略(Exponential Backoff)来避免加重服务器负担。

Promise.race() + Fetch

以下是使用 JavaScript 和 Promise 封装的一个带有 超时重试 功能的请求方法。这个方法基于 fetch API,并利用 Promise 实现超时控制和重试逻辑。

封装代码

javascript 复制代码
/**
 * 带有超时和重试功能的请求方法
 * @param {string} url - 请求的URL
 * @param {Object} options - fetch的配置选项
 * @param {number} timeout - 超时时间(毫秒)
 * @param {number} maxRetries - 最大重试次数
 * @returns {Promise<Response>} - 返回fetch的响应
 */
function fetchWithRetry(url, options = {}, timeout = 5000, maxRetries = 3) {
    return new Promise(async (resolve, reject) => {
        let retries = 0;

        // 发起请求
        const attemptFetch = async () => {
            try {
                // 创建一个超时 Promise
                const timeoutPromise = new Promise((_, reject) => {
                    setTimeout(() => reject(new Error("请求超时")), timeout);
                });

                // 发起 fetch 请求
                const fetchPromise = fetch(url, options);

                // 使用 Promise.race 实现超时控制
                const response = await Promise.race([fetchPromise, timeoutPromise]);

                // 如果响应状态码不是2xx,抛出错误
                if (!response.ok) {
                    throw new Error(`请求失败,状态码: ${response.status}`);
                }

                // 请求成功,返回响应
                resolve(response);
            } catch (error) {
                retries++;
                console.warn(`请求失败,重试次数: ${retries}, 错误: ${error.message}`);

                // 如果达到最大重试次数,抛出错误
                if (retries >= maxRetries) {
                    reject(new Error(`请求失败,已达到最大重试次数: ${maxRetries}`));
                } else {
                    // 否则,继续重试
                    attemptFetch();
                }
            }
        };

        // 开始第一次请求
        attemptFetch();
    });
}

// 使用示例
(async () => {
    try {
        const url = "https://jsonplaceholder.typicode.com/posts/1";
        const response = await fetchWithRetry(url, {}, 2000, 3); // 超时2秒,最大重试3次
        const data = await response.json();
        console.log("请求成功:", data);
    } catch (error) {
        console.error("请求最终失败:", error.message);
    }
})();

代码说明:

  1. 超时控制

    • 使用 Promise.race 实现超时功能。
    • 如果 fetch 请求在指定时间内未完成,超时 Promise 会先完成,从而中断请求。
  2. 重试机制

    • 使用递归函数 attemptFetch 实现重试逻辑。
    • 如果请求失败(超时或响应状态码非2xx),则重试,直到达到最大重试次数。
  3. 错误处理

    • 如果请求失败,会记录错误并重试。
    • 如果达到最大重试次数,抛出最终错误。
  4. 使用示例

    • 调用 fetchWithRetry 方法时,传入 URL、配置选项、超时时间和最大重试次数。
    • 请求成功后,返回响应数据;失败后,抛出错误。

示例输出:

  • 如果请求成功:

    css 复制代码
    请求成功: { userId: 1, id: 1, title: "...", body: "..." }
  • 如果请求失败:

    makefile 复制代码
    请求失败,重试次数: 1, 错误: 请求超时
    请求失败,重试次数: 2, 错误: 请求超时
    请求失败,重试次数: 3, 错误: 请求超时
    请求最终失败: 请求失败,已达到最大重试次数: 3

注意事项:

  1. 浏览器兼容性

    • fetchPromise 在现代浏览器中支持良好,但在旧版浏览器中可能需要 polyfill。
    • 如果需要兼容旧版浏览器,可以使用 axios 库替代 fetch
  2. 重试间隔

    • 当前代码是立即重试。如果需要增加重试间隔,可以在重试前添加 await new Promise(resolve => setTimeout(resolve, delay))
  3. 性能优化

    • 如果请求失败的原因是服务器过载,建议增加指数退避策略(Exponential Backoff)来避免加重服务器负担。

扩展:指数退避策略

如果需要实现指数退避策略(每次重试间隔时间逐渐增加),可以修改重试逻辑如下:

javascript 复制代码
const delay = Math.pow(2, retries) * 1000; // 指数退避,例如 2s, 4s, 8s
await new Promise(resolve => setTimeout(resolve, delay));
attemptFetch();

相关推荐
从零开始学习人工智能1 小时前
FastMCP:构建 MCP 服务器和客户端的高效 Python 框架
服务器·前端·网络
烛阴1 小时前
自动化测试、前后端mock数据量产利器:Chance.js深度教程
前端·javascript·后端
好好学习O(∩_∩)O1 小时前
QT6引入QMediaPlaylist类
前端·c++·ffmpeg·前端框架
敲代码的小吉米1 小时前
前端HTML contenteditable 属性使用指南
前端·html
testleaf1 小时前
React知识点梳理
前端·react.js·typescript
站在风口的猪11081 小时前
《前端面试题:HTML5、CSS3、ES6新特性》
前端·css3·html5
Xiao_die8881 小时前
前端八股之CSS
前端·css
每天都有好果汁吃2 小时前
基于 react-use 的 useIdle:业务场景下的用户空闲检测解决方案
前端·javascript·react.js
穗余2 小时前
NodeJS全栈开发面试题讲解——P10微服务架构(Node.js + 多服务协作)
前端·面试·node.js
横冲直撞de2 小时前
前端下载文件,文件打不开的问题记录
前端