Skip to content

取消、竞态与流式响应:练习答案 ​

AbortController 取消请求 ​

js
let controller
async function search(query) {
  controller?.abort('superseded')
  controller = new AbortController()
  try {
    const response = await fetch(`/search?q=${encodeURIComponent(query)}`, { signal: controller.signal })
    return await response.json()
  } catch (error) {
    if (controller.signal.aborted) return { kind: 'cancelled', reason: controller.signal.reason }
    throw error
  }
}

组件卸载时再次调用 abort;取消是控制流分支,不应显示为服务器错误。生产代码还需把 controller 保存在当前请求身份中,避免旧请求的 catch 误读新 controller。

请求序号与过期响应 ​

每次输入递增 requestId,响应提交前比较本地 id;即使旧请求没有真正取消,也不能覆盖新结果。测试先发慢请求 A,再发快请求 B,最终 UI 必须显示 B,并记录 A 为 ignored。

ReadableStream cancel 与 finally ​

读取循环在 finally 中释放 reader;用户停止时调用 reader.cancel(),服务端或生产者收到 cancel 后停止继续入队。若 chunk 在 UTF-8 字符中间被切断,复用同一个 TextDecoder({ stream: true }),不能对每个 chunk 单独解码。

章节入口核对 ​

以下入口对应本章概览或综合练习,答案核对沿用本章各知识点的实现与日志。

用心记录每一步成长