H5 Fetch 请求封装与竞态处理

举报
yd_223002268 发表于 2026/10/03 11:00:49 2026/10/03
【摘要】 H5 Fetch 请求封装与竞态处理摘要:浏览器的 Fetch API 提供 Promise 式网络请求,但业务代码仍需处理状态码、解析失败、超时、取消和过期响应。本文构建一个轻量请求封装,并说明搜索和页面切换中的竞态处理方法。 一、理解 Fetch 的错误语义Fetch 在网络中断、请求被取消等情况下会拒绝 Promise;收到 404 或 500 时通常仍会正常返回 Response。...

H5 Fetch 请求封装与竞态处理

摘要:浏览器的 Fetch API 提供 Promise 式网络请求,但业务代码仍需处理状态码、解析失败、超时、取消和过期响应。本文构建一个轻量请求封装,并说明搜索和页面切换中的竞态处理方法。

一、理解 Fetch 的错误语义

Fetch 在网络中断、请求被取消等情况下会拒绝 Promise;收到 404 或 500 时通常仍会正常返回 Response。因此不能只靠 catch 判断服务端是否成功,还要检查 response.ok。

async function readJson(path, options = {}) {
  const response = await fetch(path, {
    ...options,
    headers: {
      Accept: "application/json",
      ...options.headers,
    },
  });

  if (!response.ok) {
    throw new HttpError(response.status, response.statusText);
  }

  return response.json();
}

调用方需要决定返回体为空、内容不是 JSON 或服务端字段错误时如何处理。请求层不要假定所有响应都一定含有同一种数据。

二、用 AbortController 取消请求

AbortController 可以让页面在离开或查询条件变化时取消不再需要的请求:

const controller = new AbortController();

try {
  const data = await readJson(requestPath, { signal: controller.signal });
  render(data);
} catch (error) {
  if (error.name !== "AbortError") showError(error);
}

function dispose() {
  controller.abort();
}

取消后无需展示“网络失败”提示。组件卸载、路由切换或用户发出新查询时,都应取消不再使用的请求。

三、为请求设置超时

可将超时控制器与调用方的取消信号合并。环境支持 AbortSignal.timeout 和 AbortSignal.any 时可直接组合;需兼容较老环境时,则用计时器触发 AbortController,并在完成后清除计时器。

超时属于一种取消原因,错误界面可以与用户主动离开区分。超时时间应按请求用途设置;大文件上传和轻量列表读取不应强制使用相同阈值。

四、保护搜索结果顺序

快速输入可能产生多个并行请求。即使取消旧请求,某些计算或缓存层未必及时停止;可同时使用递增序号,只接受最新请求结果:

let requestVersion = 0;
let activeController;

async function search(query) {
  const version = ++requestVersion;
  activeController?.abort();
  activeController = new AbortController();

  try {
    const result = await readJson(buildSearchPath(query), {
      signal: activeController.signal,
    });
    if (version === requestVersion) renderResults(result);
  } catch (error) {
    if (error.name !== "AbortError" && version === requestVersion) {
      showSearchError(error);
    }
  }
}

序号解决“较旧结果最后返回并覆盖新结果”的问题;取消则减少不必要工作。两者解决的问题不同,必要时可以一起使用。

五、统一处理请求体与错误

提交 JSON 时显式设置内容类型并序列化对象。服务端错误体可能是 JSON、文本或空内容,因此错误封装可以安全尝试解析,再提供状态码和业务错误码。不要直接把内部异常堆栈展示给用户。

鉴权令牌应从受控的认证模块注入;记录日志前清除敏感请求头和个人数据。不要在全局封装中无条件重试所有 POST,因为重复提交可能产生副作用。

六、组件中的状态管理

请求页面可用明确的 idle、loading、success 和 error 状态,避免多个布尔值互相矛盾。发起请求时进入 loading;成功后检查结果仍对应当前输入;失败时提供可恢复动作;卸载时清理监听和请求。

加载状态应与数据策略一致。刷新时保留旧内容可以减少闪烁,而首次进入页面可展示占位状态。请求封装负责传输,不应替页面决定空态和交互文案。

七、并发与缓存边界

同一资源的并发读取可以合并请求或由缓存层复用结果,但缓存键必须包含影响响应的参数和用户身份。退出账号后要清理用户隔离数据。缓存失效与重试策略属于数据层职责,需明确时效和一致性要求。

八、常见问题

  1. 不把 HTTP 错误状态误当成 Fetch 拒绝。
  2. 不把用户取消渲染为服务端故障。
  3. 对有副作用的请求谨慎自动重试。
  4. 页面销毁后停止更新 DOM,避免残留异步任务。
  5. 解析和校验数据结构,不能把 response.json() 成功等同于数据有效。

九、总结

可靠的 Fetch 使用需要状态码检查、取消清理、超时语义和响应校验。搜索等高频场景还需要处理竞态,确保只有当前请求能更新界面。将传输错误与页面状态分开建模,封装才既可复用又不会隐藏业务决策。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。