

























@@ -27,6 +27,7 @@ type LookupCallback = (
2727) => void;
28282929type LookupResult = LookupAddress | LookupAddress[];
30+const DISPATCHER_CLOSE_TIMEOUT_MS = 100;
30313132export class SsrFBlockedError extends Error {
3233constructor(message: string) {
@@ -551,19 +552,55 @@ export function createPinnedDispatcher(
551552);
552553}
553554555+type ClosableDispatcher = {
556+close?: () => Promise<void> | void;
557+destroy?: () => void;
558+};
559+560+function destroyDispatcher(candidate: ClosableDispatcher): void {
561+try {
562+candidate.destroy?.();
563+} catch {
564+// ignore dispatcher cleanup errors
565+}
566+}
567+568+async function waitForDispatcherClose(candidate: ClosableDispatcher): Promise<void> {
569+const close = candidate.close;
570+if (typeof close !== "function") {
571+destroyDispatcher(candidate);
572+return;
573+}
574+let timeout: ReturnType<typeof setTimeout> | undefined;
575+try {
576+await Promise.race([
577+Promise.resolve(close.call(candidate)),
578+new Promise<void>((resolve) => {
579+timeout = setTimeout(() => {
580+timeout = undefined;
581+destroyDispatcher(candidate);
582+resolve();
583+}, DISPATCHER_CLOSE_TIMEOUT_MS);
584+timeout.unref?.();
585+}),
586+]);
587+} catch (err) {
588+destroyDispatcher(candidate);
589+throw err;
590+} finally {
591+if (timeout) {
592+clearTimeout(timeout);
593+}
594+}
595+}
596+554597export async function closeDispatcher(dispatcher?: Dispatcher | null): Promise<void> {
555598if (!dispatcher) {
556599return;
557600}
558-const candidate = dispatcher as { close?: () => Promise<void> | void; destroy?: () => void };
601+const candidate = dispatcher as ClosableDispatcher;
559602try {
560-if (typeof candidate.close === "function") {
561-await candidate.close();
562-return;
563-}
564-if (typeof candidate.destroy === "function") {
565-candidate.destroy();
566-}
603+await waitForDispatcherClose(candidate);
567604} catch {
568605// ignore dispatcher cleanup errors
569606}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。