DEBUG.WIKI
PanstarCloud:部署应用,接入 AI,云服务器与 AI 网关
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
搬瓦工;先看线路,再选 VPS;CN2 GIA · 对应线路套餐;查看线路 →

Ky 替换 signal 后,父控制器仍会取消请求

派生 Ky 客户端使用 replaceOption(signal),父实例的取消仍生效时,检查信号合并实现。区分替换、组合与请求已取消,保留超时策略。

父 Ky 实例绑定了一个 AbortSignal,派生实例又用 replaceOption() 换成新的 signal。父控制器一取消,派生请求却仍抛 AbortError。这种情况下,应检查信号是否真的替换,不能只看最终配置对象表面上的 signal。

旧实现会先收集参与合并的 AbortSignal,再处理 replaceOption 包装。包着新 signal 的值不是 AbortSignal 实例,旧信号却已留在收集数组中;最后通过 AbortSignal.any() 组合时,父级信号又被带了回来。

普通 signal 合并与显式替换有不同含义

派生实例同时受父级和本次控制器管理,有时正是业务需要。只有明确要求派生客户端脱离父级取消生命周期时,才应替换它。不要为了消除一次 AbortError,全局把多个信号的组合都关掉。

正式 Ky 2.2.0 会先解开 replaceOption,再处理顶层 signal。显式替换或将 signal 设为 undefined 时,会先清空已累计的父级信号。以下示例只创建客户端,没有发请求:

import ky, { replaceOption } from 'ky';

const parentController = new AbortController();
const childController = new AbortController();

const base = ky.create({ signal: parentController.signal });
const independent = base.extend({
  signal: replaceOption(childController.signal),
});

在这一正式实现下,independent 的调用方取消信号来自 childController。base 中的认证、超时、请求钩子等其他选项仍按各自合并规则继承。replaceOption 只包住 signal,不是在重建整个客户端。

如果派生客户端本来应该跟随页面退出而取消,就不适合用这段配置把父级生命周期移除。独立取消也不会移除 Ky 自己的请求超时;不要把超时错误误判成旧父信号仍被继承。

旧版本不要靠 null 猜测清除行为

旧实现中,传入 undefined 或 null 也可能没有清掉已经收集的父信号。因此,在该路径存在问题的版本里反复换这几个值,并不能证明取消关系已经解除。

优先在实际安装包中核对解包和信号收集顺序,再采用包含修正的正式版本。当前可确认 2.2.0 有上述处理,不据此声称所有较早版本都受影响,也不把某个分支补丁当成已发布版本。

暂不能升级、又确实需要完全不同生命周期时,可以评估用 ky.create() 从完整业务配置创建新客户端。它不会继承旧实例:认证、超时、错误处理和其他钩子必须逐项写回,不能只复制 signal 后直接替换现有封装。

已经 aborted 的信号不能恢复成未取消状态。复用同一个 childController 发后续请求,会把它们立即取消;每个新的生命周期需要新的控制器,不应删除异常或吞掉它来伪装成功。

在受控的只读慢响应上分别验证父取消、子取消、正常完成和自然超时。显式替换场景中,父取消不应终止派生请求,子取消应终止它;同时核对底层网络记录,不能仅凭业务 Promise 的状态判断请求已停止。