According to MDN, messages in the JavaScript event loop "run to completion".
(https://developer.mozilla.org/docs/Web/JavaScript/Event_loop#run-to-completion)
But I have created a case where this does not seem to happen.
abortController1 = new AbortController()
abortController2 = new AbortController()
abortController1.signal.addEventListener("abort", () =>
{
console.log("abort 1 start")
abortController2.abort()
console.log("abort 1 end")
})
abortController2.signal.addEventListener("abort", () =>
{
console.log("abort 2")
})
abortController1.abort()
Output:
abort 1 start
abort 2
abort 1 end
I was expecting to see this output:
abort 1 start
abort 1 end
abort 2
Can someone please explain what’s going on here?
EDIT (possible clues) –
2
Answers
When an event is triggered directly by code, it runs the listeners synchronously. The MDN documentation for dispatchEvent() explains this:
While this doesn’t mention
abort()
specifically, I see no reason why it wouldn’t be treated similarly.It’s just an example of a synchronous event.
The fire an event algorithm is synchronous. Another notorious example where this algo is called synchronously is in
HTMLElement#click()
, orEventTarget#dispatchEvent()
(see this very related Q/A for more details).The confusion comes from the fact that in most cases this algorithm is actually wrapped in a queue a task call, or from an algorithm that runs in parallel.
In the case of
AbortController#abort()
the signal abort algorithm will run the abort steps synchronously, which will fire the abort event, also synchronously.This is a pure design choice. It was deemed that consumers of the
AbortSignal
would want to react synchronously, so that after your call toabort()
you can be sure the side-effects to this call would already have kicked in.Below snippet tests a non exhaustive list of other such synchronous events from HTML: