A catalogue button starts an asynchronous action. During its listener, event.currentTarget identifies the button. Later, code reads the same event object and finds null. The button may still be on screen. The missing value describes the event's dispatch state, not the disappearance of the element.
The short answer is to capture the reference or value needed while the listener is being invoked. currentTarget is dispatch metadata: it identifies the target whose listener is currently being invoked, and dispatch cleanup resets it. Retaining the event object does not freeze that metadata. Retaining the element reference also does not freeze the element's later attributes, geometry or role.
This guide uses an original catalogue example with an explicitly pending promise. The promise is released only after dispatchEvent has returned, so the deferred continuation is known to follow dispatch cleanup. That controlled ordering matters: an unexplained claim that every await resumes after every kind of event dispatch would be too broad.
This specialist guide belongs to the Websites root. It also connects to The Gold Standard of Education | Learning That Transfers into Life and the How X Works hub. The worked cases are original teaching examples; their numbers are stipulated so that the reasoning can be checked.
eduKateSG · Websites
Find your next learning step
Capture the listener owner or action value during dispatch, then check its later relevance. Follow a controlled pending gate, delegation, path observations and default cancellation.
ROUTE 1 · CHAPTERS 1–4
Understand dispatch context
Identify the event fields and prove when deferred work runs.
ROUTE 2 · CHAPTERS 5–8
Capture the intended input
Choose references, earlier values and delegated action records.
ROUTE 3 · CHAPTERS 9–12
Respect dispatch boundaries
Distinguish paths, default cancellation, receiver conventions and diagnostic observations.
ROUTE 4 · CHAPTERS 13–15
Manage later work
Account for redispatch, asynchronous errors and retained references.
ROUTE 5 · CHAPTERS 16–18
Verify and transfer
Use controlled checks and a changed catalogue before explaining the repair.
Chapter contents
Understand dispatch context · Chapters 1–4
1. Give the action a concrete owner
2. Separate target from currentTarget
Capture the intended input · Chapters 5–8
5. Retain the reference before suspension
6. Capture values when values are the real requirement
Respect dispatch boundaries · Chapters 9–12
9. Preserve a path observation deliberately
10. Keep default cancellation within its decision window
Manage later work · Chapters 13–15
13. Consider redispatch as a new dispatch history
Verify and transfer · Chapters 16–18
16. Test the narrow claim with controlled objects
Imagine a catalogue containing a button labelled Request explanation. Its listener starts work that will eventually add a small explanation beside that button. We call this button A. A surrounding catalogue panel is P, and a small icon inside the button is I. These names distinguish three objects a careless handler might confuse.
The listener's immediate job is to identify the intended request and remember the information needed later. The deferred job is to decide whether the result still belongs in the current catalogue. The platform's event dispatch supplies information for the immediate job, but it does not implement the application's later ownership policy.
For the first exercise, register the listener directly on A. Construct an ordinary event for a controlled dispatch on A, and keep the asynchronous continuation behind a pending gate. During this invocation, reading currentTarget gives A. This is an observation at a defined stage, before the gate opens.
Do not start with a network request whose completion is unpredictable. A pending promise controlled by the exercise makes the ordering explicit. We can then ask what changes when dispatch finishes before deferred work resumes, without guessing whether a fast response or a particular microtask checkpoint altered the sequence.
The desired result is modest: retain the right information and later make a deliberate decision. A retained object reference can solve the immediate identification problem while leaving a separate question about whether that object is still the proper destination for the explanation.
CHAPTER 2 OF 18 · Understand dispatch context
2. Separate target from currentTarget
An event's target and currentTarget answer different questions. In an uncomplicated light-DOM example, target identifies the dispatch target exposed to the listener, while currentTarget identifies the object whose listener is being invoked. Event retargeting, particularly across shadow boundaries, adds further qualifications to the target observation.
Suppose the user activates icon I inside button A and the resulting event reaches a listener on panel P. In the stipulated simple light-DOM tree, the listener may observe I as target and P as currentTarget. Neither value automatically means the action button whose record the application wants to load.
A directly registered listener on A has a different currentTarget from a delegated listener on P. Moving the registration changes that dispatch observation even if the visible button and the intended catalogue action remain the same. This is why code copied between the two registration styles needs more than a change of selector.
For the controlled first exercise, dispatch directly on A without a DOM tree. Then both observations can identify A during the listener. That convenient equality is a property of the exercise. It is not a general rule that target and currentTarget are interchangeable fields.
Before deferring work, name the intended captured item precisely: listener owner, matched action button, record identifier or some combination. A variable named element is not enough when three different elements can plausibly satisfy that description. Naming the role makes later checks and explanations much easier.
CHAPTER 3 OF 18 · Understand dispatch context
3. Read the dispatch lifecycle in stages
The DOM Standard describes dispatch through a path of invocation targets. As the algorithm invokes listeners, it sets currentTarget for the relevant path entry. A listener therefore observes context for that invocation, rather than a permanent annotation saying where the event first originated.
During propagation, another listener can run with another currentTarget. The same event object participates in those stages. Saving that event object in an array does not create a separate historical event for each listener; it preserves references to the object whose dispatch-related fields continue to follow the algorithm.
At cleanup, the standard resets eventPhase to NONE, currentTarget to null and the event path to an empty list. Some target clearing is also conditional on the dispatch circumstances. These are specified state changes, not evidence that the browser prematurely forgot a still-needed application variable.
In the catalogue, the listener reads currentTarget while its invocation is active and stores that value in a local constant named listenerOwner. After cleanup, event.currentTarget can be null while listenerOwner still refers to A. The two reads come from different storage locations with different lifetimes.
This distinction explains the symptom without blaming asynchronous functions. The dispatch field is temporary context. The local binding retains the value obtained at the earlier point. Whether the object that value references has changed is the next question, not a reason to treat both forms of storage as equivalent.
CHAPTER 4 OF 18 · Understand dispatch context
4. Build a gate that proves the ordering
Create a pending promise and retain a separate function that resolves it. In the listener, first save event.currentTarget. Then await that pending promise. Outside the listener, call dispatchEvent. Only after dispatchEvent returns should the exercise resolve the gate. Finally, allow the promise continuation to run and collect its observations.
The synchronous dispatch call does not wait for the listener's returned promise to fulfil. The listener runs up to its suspension point, and dispatch can finish the rest of its work. Because our gate remains pending throughout that call, the deferred observation cannot precede the dispatch return.
Use a ledger with four entries. Entry one records currentTarget inside the listener as A. Entry two records that dispatchEvent returned. Entry three opens the gate. Entry four records event.currentTarget as null and the saved listenerOwner as A. The identity comparison, rather than the button's displayed label, is what demonstrates retention.
This is more informative than writing await something and assuming its timing. If the awaited value is already fulfilled, the continuation's relation to host callback and microtask processing requires closer analysis. Our exercise deliberately removes that ambiguity by keeping the promise unresolved until dispatch cleanup has completed.
The gate is a teaching device, not a requirement to add an artificial delay to production code. Production work should capture needed information before deferring and define the actual asynchronous contract. The controlled gate simply gives the learner a sequence whose observations have one clear explanation.
CHAPTER 5 OF 18 · Capture the intended input
5. Retain the reference before suspension
The key operation is a read performed during the listener: assign event.currentTarget to a local constant. That assignment copies the reference value. It does not clone the element, move its listener registration or create a new connection between the event and the element.
Later code can use the saved reference without rereading currentTarget. In the exercise, the event field is null but the reference still identifies A. No DOM query is required to recover what the listener already knew. A fresh query would answer a different question about the current document and could find a replacement element.
This is also why destructuring the value during the listener can work. The important part is when the getter is read and where its returned value is stored. Merely wrapping the event in another object, such as a record with a property pointing to the original event, does not copy currentTarget's earlier value.
Compare two records. Record R contains the event object. Record S contains the currentTarget value read during invocation. After dispatch, R's event still exposes its current dispatch state. S's stored reference still identifies A. An object wrapper alone is not a snapshot; the selected values and the time of reading determine what was preserved.
For a null-sensitive API, check the captured value at the capture point and establish the expected type before using element-specific methods. A generic EventTarget can be something other than an Element. The first controlled test uses EventTarget deliberately, so it demonstrates reference retention without pretending to demonstrate a browser DOM method.
CHAPTER 6 OF 18 · Capture the intended input
6. Capture values when values are the real requirement
Suppose A carries a record identifier, catalogue-17, and a later operation needs to request that record. Saving A gives access to its future state. Saving the identifier string gives the earlier identifier value. Those choices have different meanings when the catalogue can repurpose or replace a button.
In a changed trace, the listener reads catalogue-17 and then waits behind the gate. Before releasing it, the application updates A's record attribute to catalogue-23. After resumption, a new read through the saved element sees the later attribute. The saved identifier string still describes catalogue-17.
Neither observation is inherently wrong. If the request represents the original activation, the earlier identifier may be the intended input. If the later task must operate on the current selection, it needs an explicit comparison or a fresh decision. Accidentally mixing an old activation with a new attribute value can request the wrong record without any null error.
The same reasoning applies to text, checked state and form values. Capture a primitive value when the operation requires the value at activation. Retain an element reference when the operation requires later access to that object. When both are needed, store both with names that express their distinct jobs.
Do not describe this as freezing the page. A string captured from an attribute is a selected observation, not a preserved component. Other values, the DOM structure and application state can all change. Capturing the minimum relevant information reduces ambiguity without promising a comprehensive historical snapshot.
CHAPTER 7 OF 18 · Capture the intended input
7. Distinguish retention from continued relevance
While the gate is closed, imagine the catalogue switches to another category and removes A. The saved reference can still identify A. Its survival as a JavaScript reference does not prove that A remains connected to the document or belongs to the current category.
If the deferred code sets A's text after removal, it may successfully alter a detached object while changing nothing visible. A log saying update completed would then overstate the user-facing result. The operation performed an object mutation; it did not necessarily update the current interface.
A connection check can help answer whether an element is in a document tree at that moment, but it is not a complete application ownership check. An old button might be reinserted in another context, or a connected panel might now represent a different record. The application's current selection and attempt identity still matter.
For the catalogue, pair the captured identifier with an attempt marker controlled by the current panel. Before committing, compare that marker with the panel's current attempt and confirm the intended destination. This is an example policy, not an Event feature. Different applications may use different ownership records.
The useful separation is between retained identity, current state and current permission. currentTarget retention addresses the first. Reading attributes addresses part of the second. Checking the active request or selection addresses the third. A single non-null reference cannot establish all three at once.
Now register one listener on panel P and let it handle several buttons. During its invocation, currentTarget identifies P. If deferred work needs the activated action button, simply saving currentTarget preserves the panel, not the button. The code must identify the intended action while it has the relevant dispatch information.
In the stipulated light-DOM catalogue, the listener examines the event target, finds the appropriate ancestor action button and verifies that the match belongs to P's intended region. It then saves the matched button and its record identifier. The matching rule should exclude unrelated nested widgets and actions outside the panel's responsibility.
If the activation starts on icon I, using target directly as the action button can fail. If the listener is moved to a larger ancestor, an unbounded ancestor search can also choose an unintended match. Delegation is an application routing decision layered on top of propagation, not an automatic conversion of target into the desired control.
The asynchronous continuation should use the already resolved action record, subject to its later ownership checks. Rerunning a selector after the gate opens can find a different button with the same attribute or identifier. That may be useful for a current-view lookup, but it should not be confused with retaining the original invocation's match.
Shadow DOM requires additional care because exposed targets and composed paths have encapsulation rules. This guide's matching trace assumes the stated simple light-DOM tree. When a component crosses a shadow boundary, design against its public event contract rather than assuming access to an internal button from an outside listener.
CHAPTER 9 OF 18 · Respect dispatch boundaries
9. Preserve a path observation deliberately
A learner sometimes tries to solve the problem by calling composedPath later. That method reflects the event's path information under its specified visibility rules. Dispatch cleanup empties the stored event path, so retaining the event object is not a promise that a later call will reconstruct the earlier propagation route.
If the route itself is required, call composedPath at the appropriate invocation point and retain the returned array. The array preserves the reference sequence obtained then. It does not freeze those nodes, their parent relationships or their membership in the current document after the event has finished.
In a paper trace, the listener saves a path containing I, A and P among the relevant simple-tree entries. Before the gate opens, A is moved to a different panel. The saved array still records those earlier references in their observed order. A fresh traversal from A follows its current structure instead.
These two records can usefully coexist: the earlier path explains the activation route; the current tree explains where the element now lives. Treating the array as a current ancestry certificate would give it an authority it does not have. The same applies if a node is removed rather than moved.
For closed shadow roots, the path visible to a listener is constrained by the standard. Capturing it does not bypass encapsulation or reveal everything about the original activation. State the listener's location and the component's event contract before drawing conclusions from which references appear in its observed path.
CHAPTER 10 OF 18 · Respect dispatch boundaries
10. Keep default cancellation within its decision window
An asynchronous listener introduces another lifetime question: when must it decide whether to cancel a default action? Returning a promise from a listener does not generally make DOM dispatch await the eventual result as permission for that action. A later continuation is not a universal veto channel.
In a controlled cancelable synthetic event, call preventDefault during the listener before the pending gate. dispatchEvent can then report that cancellation through its return value. Open the gate afterwards and inspect the already returned result. Later work cannot travel back and change what the dispatch call returned.
Reverse the experiment: do not cancel before the gate, let dispatchEvent return and record its value, then attempt the later decision. Whatever state a later method call changes on the event object, it cannot retroactively alter the earlier return value or undo a browser action that has already proceeded.
Real default actions have event-specific rules, and passive listeners impose another restriction on cancellation. Consult the listener-options guide and the relevant element or event specification. The synthetic event exercise tests a dispatch contract; it does not simulate every navigation, form submission or user activation rule.
If an interface needs asynchronous validation before an application action, design that action explicitly: make the immediate event decision where permitted, start validation and later perform the authorised application step if its conditions still hold. Avoid treating a delayed read of the event as an invitation to keep the platform's original decision window open indefinitely.
CHAPTER 11 OF 18 · Respect dispatch boundaries
11. Do not use this as an unexplained substitute
An ordinary function listener can receive a this value associated with the current invocation target under the event listener calling rules. An arrow function instead uses its lexical this. Changing a handler into an arrow, binding it to another object or calling a helper through a different receiver can therefore change what an unexplained this expression means.
Saving an explicit listenerOwner inside the listener makes the intended source visible. It does not require a reader to reconstruct the handler's function form and surrounding lexical context. That clarity is particularly useful when the handler contains nested callbacks with their own calling conventions.
In the catalogue, a normal listener might correctly identify A through its invocation context during the initial call. Move the logic into an arrow declared in a component object and that assumption may fail. The event's currentTarget read still has a specified event-dispatch meaning at the original invocation point, independent of a helper's receiver convention.
The appropriate choice is not a rule forbidding this everywhere. It is a requirement to explain which context a value represents. If the codebase deliberately uses a normal function's listener receiver, retain and name it before deferral. If it uses explicit event metadata, retain that value and validate its expected type.
When reviewing a repair, check that it solves the observed lifetime problem rather than merely changing the spelling of the same late read. A helper that reads event.currentTarget after the gate still sees the later field. Moving that read into a function named getButton does not restore the earlier invocation context.
CHAPTER 12 OF 18 · Respect dispatch boundaries
12. Account for multiple listeners on the same event
Suppose A has two listeners, L1 and L2. L1 saves the event object for later; L2 saves currentTarget during its invocation. Both can observe A at their own immediate points. After dispatch, the saved event reference from L1 does not preserve a private currentTarget value for L1.
If the event also reaches P, a listener there can observe P as currentTarget during that invocation. A diagnostic logger that stores only event references and expands them later may show the same later state for every entry. That does not prove every listener originally observed null or the same invocation target.
To make a useful diagnostic record, copy the selected values at the observation point: listener label, currentTarget reference, event phase and any relevant record identifier. Primitive fields record values at that time; referenced objects remain objects whose state may evolve. Label that distinction in the log design.
For a paper exercise, compare three entries produced while invoking A, invoking P and after cleanup. The intended currentTarget sequence is A, P, null in the stipulated propagation case. An array containing the same event object three times cannot on its own preserve that sequence of historical field values.
This is a general debugging habit with a specific event application: distinguish recording an object reference from recording selected observations. It does not require serialising the whole event or attempting to clone DOM nodes. The smallest useful record is often both clearer and more reliable than a large mutable object inspected long after the event.
CHAPTER 13 OF 18 · Manage later work
13. Consider redispatch as a new dispatch history
A script can reuse an event object for a later permitted dispatch after the earlier dispatch has completed. That possibility is another reason to avoid treating a retained event as an immutable historical record. During the later dispatch, the object's dispatch-related state follows the new sequence.
Use ordinary standalone EventTargets A and B for a controlled example. Dispatch the event on A, retain the observations made there, allow cleanup, and later dispatch the same event object on B. A later target observation can concern B. The earlier saved reference to A is not changed into B by this reuse.
This example concerns script-created dispatches. It is not a recommendation to replay trusted user events or assume a synthetic event has the authority of genuine user activation. Those are different platform rules. It simply shows why a reusable event object is not a permanent record of one earlier target.
Attempting redispatch while an event is already being dispatched is also a different case, with dispatch-state restrictions. Keep the exercise sequential: first dispatch returns, then another dispatch begins. Removing that boundary would change the test instead of extending the same result.
If an audit trail must represent activation A, store the relevant application identifier and observations under an application record. Do not rely on a retained event's future target or phase to reconstruct that earlier action. Event objects serve dispatch; application records serve the history the application chooses to retain.
CHAPTER 14 OF 18 · Manage later work
14. Treat errors from deferred work explicitly
An async listener returns a promise, but ordinary event dispatch does not turn that promise into an awaited application result. If the continuation throws, the application needs an explicit error-handling path appropriate to its asynchronous work. Retaining currentTarget prevents one class of error; it does not make the whole operation succeed.
For the catalogue, the continuation might fail while parsing the explanation or while applying it to an obsolete panel. A catch boundary around the intended asynchronous operation can report the appropriate state and clean up that attempt. An unhandled failure should not leave the button indefinitely claiming that work is still in progress.
Separate a dispatch failure from a later operation failure in the log. The dispatch may have completed normally before the gate opened. A later exception does not imply that the original dispatchEvent call returned an error result or waited for the explanation operation to finish.
Where several operations are combined, use the Promise.all lesson to distinguish an aggregate rejection from cancellation of remaining work. The event lifetime problem is one layer lower: what input did each operation retain from the activation? Correct aggregation cannot recover an input value that was never captured when it was available.
A useful recovery path therefore begins with sound input capture, continues with explicit operation outcome handling and ends with a current-ownership check before display. These are separate responsibilities, each with a testable condition. Solving only the null field symptom should not be mistaken for proving the entire asynchronous interaction correct.
CHAPTER 15 OF 18 · Manage later work
15. Keep retained references only as long as needed
A closure can keep a saved element reference reachable while deferred work remains reachable. Capturing it intentionally is useful, but retaining many completed attempt records indefinitely can also retain objects the interface no longer needs. Reference lifetime deserves an explicit cleanup policy in long-running pages.
Do not infer memory reclamation from removal alone. A detached element can remain reachable through application state, pending work or diagnostic history. Conversely, clearing an application reference is not a promise about an exact instant of garbage collection. The useful application action is to release references it no longer needs.
The catalogue can keep the current attempt record while it is active, clear obsolete records when their work and reporting are settled, and avoid storing whole event objects in a permanent array. This is a design example rather than a universal disposal API for events.
If a result needs only the earlier record identifier, retaining that primitive may be enough. If it must update a particular object, the element reference may be necessary until the commit decision. Choosing the minimum information for the task makes both ownership and cleanup easier to reason about.
For a changed-context check, cancel an attempt before releasing its gate. The saved reference can still exist, but the attempt should no longer commit to the panel under the chosen policy. Cleanup and cancellation are not magical erasure; they are explicit changes to what the application keeps and what later work may do.
CHAPTER 16 OF 18 · Verify and transfer
16. Test the narrow claim with controlled objects
A small EventTarget test can verify the central sequence without a browser tree. Create A, a script-created Event and a pending gate. In the listener, save currentTarget, await the gate and then record the saved reference together with the event's currentTarget and composedPath length.
Call dispatchEvent, record currentTarget immediately after it returns, and only then resolve the gate. The expected post-return value is null. In the continuation, the saved reference still equals A, currentTarget is null and the path is empty. These observations test cleanup and retention under the explicit ordering.
We also check a distinct event created as cancelable, with cancellation performed synchronously before the gate. Its dispatch return records that cancellation. A separate sequential redispatch check shows that the same event object can have a later target while the earlier saved owner remains unchanged.
The accompanying controlled checks were run with Node's EventTarget implementation, version 24.22.1. They do not contain browser elements, propagation through a DOM tree, shadow roots, user activation or navigation. Those parts of this guide are specification-based explanations and stipulated paper traces, not device measurements.
This limitation is useful rather than inconvenient. It tells us exactly what the test can establish. To verify a real delegated catalogue, add a browser-specific test with the actual tree, matching rules and replacement sequence. Do not label a successful standalone EventTarget check as proof of every interface behaviour described here.
CHAPTER 17 OF 18 · Verify and transfer
17. Transfer the idea to a changed catalogue
Try the full reasoning with new conditions. The listener is now on P. Activation begins on icon I inside button A, whose identifier is catalogue-17. While the gate is closed, A is removed and a new button B with the same visible label appears for catalogue-23.
The immediate listenerOwner is P. The matched action reference is A. The captured identifier is catalogue-17. After resumption, event.currentTarget is null in this deliberately post-dispatch continuation. A fresh selector might find B, but B is not the earlier matched object merely because its label is the same.
If the intended operation is to fetch the explanation requested by the original activation, use catalogue-17 as the input. If the current panel no longer permits that attempt to render, decline the commit. That result is compatible with the request completing successfully; successful work and current display permission are different facts.
If instead the product intends every activation to apply to whatever selection is current at completion, state that unusual policy explicitly and design its checks accordingly. Do not arrive at it accidentally by rereading a mutable button attribute after waiting. An interface policy should be a decision that a reviewer can see.
The transfer question is therefore not simply whether a variable is null. Ask which object was observed, which value was captured, which changes occurred while waiting and which current authority permits a result to appear. Those questions keep the event-specific lesson useful when the catalogue layout and operation duration change.
A precise explanation says that currentTarget belongs to the active dispatch invocation and is reset during cleanup. The handler captured the required owner or action record while that information was available. Deferred work later uses those retained values subject to a separate relevance check.
It does not say the browser destroyed the button, that async functions cannot use DOM elements, or that every await has identical host timing. It does not promise that a saved reference freezes attributes or that a captured path remains the current tree. Those misconceptions would turn a small repair into a larger maintenance problem.
When a report still fails after capture, inspect the next boundary. Was the captured object the delegated panel instead of the action button? Did its identifier change? Was it replaced? Did a later attempt become current? Did the asynchronous operation itself reject? Each question leads to different evidence and a different repair.
For a final check, remove the event reference from the deferred operation's input entirely where it is unnecessary. Pass the intended action identifier, destination reference and attempt marker explicitly. The operation then advertises what it depends on, and its caller owns the task of capturing those values at the right time.
The lasting skill is to distinguish temporary dispatch context from retained application input. Once that boundary is visible, the null observation becomes expected, the capture point becomes obvious and the remaining interface decisions can be tested directly. That is a more dependable explanation than treating the event object as a permanent snapshot of a click.
Continue through the verified reading route
Trace listener registration and dispatch options
Trace listener registration and dispatch options. Check capture, once, passive and signal behaviour when the question concerns listener invocation or timely cancellation.
Separate node cloning from listener registration
Separate node cloning from listener registration. Understand why a replacement element does not inherit the original registered callback or its instance ownership.
Handle the eventual operation outcomes
Handle the eventual operation outcomes. Connect deferred work to promise aggregation without assuming rejection cancels other work.
Connected practical checks
The Gold Standard of Websites | Separating Fetch Rejection from an HTTP Error Response
The Gold Standard of Websites | Separating Fetch Rejection from an HTTP Error Response. Follow retained activation inputs into response-status checks, JSON parsing and current display permission.
Frequently asked questions
Does currentTarget become null because my element was removed?
Removal is not required. Dispatch cleanup resets the field even if the element remains visible. Check the event lifecycle separately from the saved element's connection and current application role.
Can I keep the whole event for later?
You can retain its reference, but that does not preserve historical values for dispatch-related fields. Capture the particular values or references needed at the invocation point instead of assuming the object is an immutable record.
Is target always the button I need?
No. A nested icon may be the target in a simple tree, and shadow-boundary retargeting adds other rules. Resolve the intended action using the component's event contract and a bounded matching rule.
Does saving an element freeze its record identifier?
No. A later attribute read observes the object's later state. Capture the identifier value at activation if that earlier value is the intended request input, then separately check whether its result may still render.
Will dispatchEvent await my async listener?
Ordinary DOM event dispatch does not await the returned promise as the application's eventual result. Handle the asynchronous outcome explicitly and make any timely cancellation decision under the relevant event rules.
Does the controlled test prove browser delegation works?
No. Its standalone EventTargets verify cleanup and retention with an explicitly ordered gate. A real DOM, shadow component, matching rule and replacement sequence require their own browser-level evidence.
Authoritative sources and further reading
WHATWG DOM Standard: event dispatch. Invocation targets, dispatch cleanup, path handling and cancellation state.
WHATWG DOM Standard: Event interface. Meaning of target, currentTarget, eventPhase and composedPath; target observations remain subject to retargeting.
WHATWG DOM Standard: EventTarget. Listener registration, invocation and dispatchEvent contract.
WHATWG HTML Standard: event loops. Host task and microtask processing; the worked gate deliberately avoids assuming all await continuations have one dispatch ordering.
Return to the Websites subject guide, The Gold Standard of Education, or the How X Works hub.