Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

`fetchEventSource` doesn't abort when passing in an already aborted signal

未关闭
#98 0 条评论 9 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
3/5
预计耗时
1-2 天
新手友好度
35/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
停滞
技术栈
typescript
领域
api

调研方向

从 issue 中所示的 fetchEventSource 实现开始,使用一个已经 abort 的 AbortController signal 重现该情况。验证请求会立即 abort 并以 abort error reject,然后在能够确定相关测试位置的情况下,为此行为添加或更新 coverage。

由索引模型根据 Issue 内容生成。

描述

Javascript's default fetch rejects with an AbortError when passing an already aborted signal:

const controller = new AbortController()
controller.abort()
await fetch("https://google.com", { signal: controller.signal })
Uncaught:
DOMException [AbortError]: This operation was aborted
    at node:internal/deps/undici/undici:13392:13
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async REPL17:1:33

However, when using fetch-event-source it fails to detect that the signal is already aborted:

const controller = new AbortController()
controller.abort()
await fetchEventSource("https://any-website-supporting-sse.com", { signal: controller.signal })
// the call above is never aborted

This doesn't abort the fetch.

The reason is that fetchEventSource creates a new aborter and subscribes to the original signal's abort event to then abort its own controller, but the abort event does not trigger retroactively (i.e. if the signal is already aborted). Here's the relevant snippet from the fetchEventSource implementation:

let curRequestController: AbortController;

function dispose() {
  // ...
  curRequestController.abort();
}

inputSignal?.addEventListener('abort', () => {
  // this callback is not called if the inputSignal is already aborted!
  // hence, curRequestController is not aborted
  dispose();
  resolve();
});

async function create() {
  curRequestController = new AbortController();
    try {
      const response = await fetch(input, {
        ...rest,
        headers,
        signal: curRequestController.signal,
      });
      // ...
    } catch (err) {
      if (!curRequestController.signal.aborted) {
        // ...
      }
    }
};

I patched it locally as follows:

inputSignal?.addEventListener('abort', () => {
  dispose();
  // no longer resolving the promise here
  // because 1) we should reject instead of resolve when aborted
  // and 2) dispose() will abort the curRequestController.signal
  // which will cause the ongoing fetch request to throw an AbortError
  // which we will catch and then we will reject the promise with the error
});

async function create() {
  curRequestController = new AbortController();
  // use the input signal if it is already aborted
  const sig = inputSignal.aborted ? inputSignal : curRequestController.signal
    try {
      const response = await fetch(input, {
        ...rest,
        headers,
        signal: sig,
      });
      // ...
    } catch (err) {
      if (sig.aborted) {
        dispose();
        reject(err);
      } else if (!curRequestController.signal.aborted) {
        // ...
      }
    }
};
主要语言
TypeScript
星标
2.9k
派生
197
PR 合并指标
30 天内没有已合并 PR

环境准备

  • 没有 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

Azure/fetch-event-source 的其他 Issue

查看 Azure/fetch-event-source 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。