1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-21 23:04:45 -05:00

fix(ext/web): Copy EventTarget list before dispatch (#19360)

Related issue: https://github.com/denoland/deno/issues/19358.

This is a regression that seems to have been introduced in
https://github.com/denoland/deno/pull/18905. It looks to have been a
performance optimization.

The issue is probably easiest described with some code:
```ts
const target = new EventTarget();
const event = new Event("foo");
target.addEventListener("foo", () => {
  console.log('base');
  target.addEventListener("foo", () => {
    console.log('nested');
  });
});
target.dispatchEvent(event);
```
Essentially, the second event listener is being attached while the `foo`
event is still being dispatched. It should then not fire that second
event listener, but Deno currently does.
This commit is contained in:
Koen 2023-06-05 02:03:44 +02:00 committed by GitHub
parent 34dac6c6ef
commit adf41edda1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 17 additions and 2 deletions

View file

@ -245,6 +245,20 @@ Deno.test(function eventTargetDispatchShouldSetTargetInListener() {
assertEquals(called, true);
});
Deno.test(function eventTargetDispatchShouldFireCurrentListenersOnly() {
const target = new EventTarget();
const event = new Event("foo");
let callCount = 0;
target.addEventListener("foo", () => {
++callCount;
target.addEventListener("foo", () => {
++callCount;
});
});
target.dispatchEvent(event);
assertEquals(callCount, 1);
});
Deno.test(function eventTargetAddEventListenerGlobalAbort() {
return new Promise((resolve) => {
const c = new AbortController();

View file

@ -737,13 +737,14 @@ function innerInvokeEventListeners(
}
let handlers = targetListeners[type];
const handlersLength = handlers.length;
// Copy event listeners before iterating since the list can be modified during the iteration.
if (handlers.length > 1) {
if (handlersLength > 1) {
handlers = ArrayPrototypeSlice(targetListeners[type]);
}
for (let i = 0; i < handlers.length; i++) {
for (let i = 0; i < handlersLength; i++) {
const listener = handlers[i];
let capture, once, passive;