用 Promise.race 包一层计时器,只会让调用方先返回,原来的 fetch 仍可能继续占着连接。Node.js 20+ 可以直接把 AbortSignal.timeout() 传给 fetch,超时后会取消请求。
环境:Node.js 20+;Linux、macOS 或 Windows;只用内置 API。保存为 timeout-demo.mjs:
import { createServer } from 'node:http';
const server = createServer((_request, response) => {
setTimeout(() => response.end('late response'), 500);
});
server.listen(0, '127.0.0.1', async () => {
const address = server.address();
const url = `http://127.0.0.1:${address.port}`;
try {
const response = await fetch(url, {
signal: AbortSignal.timeout(100),
});
console.log(await response.text());
process.exitCode = 1;
} catch (error) {
if (error.name !== 'TimeoutError') throw error;
console.log('request timed out');
} finally {
server.close();
}
});
运行 node timeout-demo.mjs,会输出 request timed out。这里的服务故意延迟 500 毫秒,客户端在 100 毫秒后中止。手动调用 AbortController.abort() 时常见的是 AbortError,超时信号则是 TimeoutError;实际代码最好按 name 区分,不要匹配错误文案。