I pass signal into fetch. The server never answers. abort() after 8s rejects, but the socket still shows in the network panel as pending for another minute. Is that the browser keeping the request, or did I forget to abort a second fetch I chained in then()?
You aborted the first call. The then() started a second fetch with no signal. Pass the same controller.signal into both, or abort before you chain. The pending line is that second request. DevTools will keep it until the server or the tab dies.
If you wrap fetch in a timeout helper, return both the promise and the controller. I used to hide the controller and then could not abort the follow-up.