Promise.race与延迟实现请求超时控制 - 解析azu/promises-book高级技巧

Promise.race与延迟实现请求超时控制 - 解析azu/promises-book高级技巧

promises-book JavaScript Promiseの本 promises-book 项目地址: 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和延迟函数实现请求超时控制,主要内容包括:

  1. 使用delayPromise创建延迟解决的Promise
  2. 结合Promise.race实现超时控制逻辑
  3. 创建自定义TimeoutError以便区分错误类型
  4. 封装可取消的XHR请求
  5. 模块化设计的最佳实践
  6. 现代Fetch API的AbortController方案

Promise的强大之处在于它提供了清晰的异步流程控制能力。通过合理的功能分解和模块化设计,我们可以构建出既强大又易于维护的异步代码结构。

promises-book JavaScript Promiseの本 promises-book 项目地址: https://gitcode.com/gh_mirrors/pr/promises-book

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蒋素萍Marilyn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值