| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -4,9 +4,11 @@ | |||
| 4 | 4 | // in https://github.com/mysticatea/abort-controller (MIT license) | |
| 5 | 5 | ||
| 6 | 6 | const { | |
| 7 | + ArrayPrototypePush, | ||
| 7 | 8 | ObjectAssign, | |
| 8 | 9 | ObjectDefineProperties, | |
| 9 | 10 | ObjectDefineProperty, | |
| 11 | + ObjectSetPrototypeOf, | ||
| 10 | 12 | PromiseResolve, | |
| 11 | 13 | SafeFinalizationRegistry, | |
| 12 | 14 | SafeSet, | |
@@ -372,18 +374,46 @@ ObjectDefineProperty(AbortSignal.prototype, SymbolToStringTag, { | |||
| 372 | 374 | ||
| 373 | 375 | defineEventHandler(AbortSignal.prototype, 'abort'); | |
| 374 | 376 | ||
| 377 | + // https://dom.spec.whatwg.org/#dom-abortsignal-abort | ||
| 375 | 378 | function abortSignal(signal, reason) { | |
| 379 | + // 1. If signal is aborted, then return. | ||
| 376 | 380 | if (signal[kAborted]) return; | |
| 381 | + | ||
| 382 | + // 2. Set signal's abort reason to reason if it is given; | ||
| 383 | + // otherwise to a new "AbortError" DOMException. | ||
| 377 | 384 | signal[kAborted] = true; | |
| 378 | 385 | signal[kReason] = reason; | |
| 386 | + // 3. Let dependentSignalsToAbort be a new list. | ||
| 387 | + const dependentSignalsToAbort = ObjectSetPrototypeOf([], null); | ||
| 388 | + // 4. For each dependentSignal of signal's dependent signals: | ||
| 389 | + signal[kDependantSignals]?.forEach((s) => { | ||
| 390 | + const dependentSignal = s.deref(); | ||
| 391 | + // 1. If dependentSignal is not aborted, then: | ||
| 392 | + if (dependentSignal && !dependentSignal[kAborted]) { | ||
| 393 | + // 1. Set dependentSignal's abort reason to signal's abort reason. | ||
| 394 | + dependentSignal[kReason] = reason; | ||
| 395 | + dependentSignal[kAborted] = true; | ||
| 396 | + // 2. Append dependentSignal to dependentSignalsToAbort. | ||
| 397 | + ArrayPrototypePush(dependentSignalsToAbort, dependentSignal); | ||
| 398 | + } | ||
| 399 | + }); | ||
| 400 | + | ||
| 401 | + // 5. Run the abort steps for signal | ||
| 402 | + runAbort(signal); | ||
| 403 | + // 6. For each dependentSignal of dependentSignalsToAbort, | ||
| 404 | + // run the abort steps for dependentSignal. | ||
| 405 | + for (let i = 0; i < dependentSignalsToAbort.length; i++) { | ||
| 406 | + const dependentSignal = dependentSignalsToAbort[i]; | ||
| 407 | + runAbort(dependentSignal); | ||
| 408 | + } | ||
| 409 | + } | ||
| 410 | + | ||
| 411 | + // To run the abort steps for an AbortSignal signal | ||
| 412 | + function runAbort(signal) { | ||
| 379 | 413 | const event = new Event('abort', { | |
| 380 | 414 | [kTrustEvent]: true, | |
| 381 | 415 | }); | |
| 382 | 416 | signal.dispatchEvent(event); | |
| 383 | - signal[kDependantSignals]?.forEach((s) => { | ||
| 384 | - const signalRef = s.deref(); | ||
| 385 | - if (signalRef) abortSignal(signalRef, reason); | ||
| 386 | - }); | ||
| 387 | 417 | } | |
| 388 | 418 | ||
| 389 | 419 | class AbortController { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -13,7 +13,7 @@ Last update: | |||
| 13 | 13 | - common: https://github.com/web-platform-tests/wpt/tree/dbd648158d/common | |
| 14 | 14 | - compression: https://github.com/web-platform-tests/wpt/tree/5aa50dd415/compression | |
| 15 | 15 | - console: https://github.com/web-platform-tests/wpt/tree/767ae35464/console | |
| 16 | - - dom/abort: https://github.com/web-platform-tests/wpt/tree/d1f1ecbd52/dom/abort | ||
| 16 | + - dom/abort: https://github.com/web-platform-tests/wpt/tree/0143fe244b/dom/abort | ||
| 17 | 17 | - dom/events: https://github.com/web-platform-tests/wpt/tree/0a811c5161/dom/events | |
| 18 | 18 | - encoding: https://github.com/web-platform-tests/wpt/tree/5aa50dd415/encoding | |
| 19 | 19 | - fetch/data-urls/resources: https://github.com/web-platform-tests/wpt/tree/7c79d998ff/fetch/data-urls/resources | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,6 @@ | |||
| 1 | + features: | ||
| 2 | + - name: aborting | ||
| 3 | + files: "**" | ||
| 4 | + - name: abortsignal-any | ||
| 5 | + files: | ||
| 6 | + - abort-signal-any.any.js | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,23 @@ | |||
| 1 | + <!DOCTYPE html> | ||
| 2 | + <html class=test-wait> | ||
| 3 | + <head> | ||
| 4 | + <title>AbortSignal::Any when source signal was garbage collected</title> | ||
| 5 | + <link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1908466"> | ||
| 6 | + <link rel="author" title="Vincent Hilla" href="mailto:vhilla@mozilla.com"> | ||
| 7 | + <script src="/common/gc.js"></script> | ||
| 8 | + </head> | ||
| 9 | + <body> | ||
| 10 | + <p>Test passes if the browser does not crash.</p> | ||
| 11 | + <script> | ||
| 12 | + async function test() { | ||
| 13 | + let controller = new AbortController(); | ||
| 14 | + let signal = AbortSignal.any([controller.signal]); | ||
| 15 | + controller = undefined; | ||
| 16 | + await garbageCollect(); | ||
| 17 | + AbortSignal.any([signal]); | ||
| 18 | + document.documentElement.classList.remove('test-wait'); | ||
| 19 | + } | ||
| 20 | + test(); | ||
| 21 | + </script> | ||
| 22 | + </body> | ||
| 23 | + </html> | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,11 @@ | |||
| 1 | + <!DOCTYPE html> | ||
| 2 | + <meta charset="utf-8"> | ||
| 3 | + <script> | ||
| 4 | + let b; | ||
| 5 | + window.addEventListener("DOMContentLoaded", () => { | ||
| 6 | + let a = new AbortController() | ||
| 7 | + b = AbortSignal.any([a.signal]) | ||
| 8 | + a.signal.addEventListener("abort", () => { AbortSignal.any([b]) }, { }) | ||
| 9 | + a.abort(undefined) | ||
| 10 | + }) | ||
| 11 | + </script> | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -182,4 +182,59 @@ function abortSignalAnyTests(signalInterface, controllerInterface) { | |||
| 182 | 182 | controller.abort(); | |
| 183 | 183 | assert_equals(result, "01234"); | |
| 184 | 184 | }, `Abort events for ${desc} signals fire in the right order ${suffix}`); | |
| 185 | + | ||
| 186 | + test(t => { | ||
| 187 | + const controller = new controllerInterface(); | ||
| 188 | + const signal1 = signalInterface.any([controller.signal]); | ||
| 189 | + const signal2 = signalInterface.any([signal1]); | ||
| 190 | + let eventFired = false; | ||
| 191 | + | ||
| 192 | + controller.signal.addEventListener('abort', () => { | ||
| 193 | + const signal3 = signalInterface.any([signal2]); | ||
| 194 | + assert_true(controller.signal.aborted); | ||
| 195 | + assert_true(signal1.aborted); | ||
| 196 | + assert_true(signal2.aborted); | ||
| 197 | + assert_true(signal3.aborted); | ||
| 198 | + eventFired = true; | ||
| 199 | + }); | ||
| 200 | + | ||
| 201 | + controller.abort(); | ||
| 202 | + assert_true(eventFired, "event fired"); | ||
| 203 | + }, `Dependent signals for ${desc} are marked aborted before abort events fire ${suffix}`); | ||
| 204 | + | ||
| 205 | + test(t => { | ||
| 206 | + const controller1 = new controllerInterface(); | ||
| 207 | + const controller2 = new controllerInterface(); | ||
| 208 | + const signal = signalInterface.any([controller1.signal, controller2.signal]); | ||
| 209 | + let count = 0; | ||
| 210 | + | ||
| 211 | + controller1.signal.addEventListener('abort', () => { | ||
| 212 | + controller2.abort("reason 2"); | ||
| 213 | + }); | ||
| 214 | + | ||
| 215 | + signal.addEventListener('abort', () => { | ||
| 216 | + count++; | ||
| 217 | + }); | ||
| 218 | + | ||
| 219 | + controller1.abort("reason 1"); | ||
| 220 | + assert_equals(count, 1); | ||
| 221 | + assert_true(signal.aborted); | ||
| 222 | + assert_equals(signal.reason, "reason 1"); | ||
| 223 | + }, `Dependent signals for ${desc} are aborted correctly for reentrant aborts ${suffix}`); | ||
| 224 | + | ||
| 225 | + test(t => { | ||
| 226 | + const source = signalInterface.abort(); | ||
| 227 | + const dependent = signalInterface.any([source]); | ||
| 228 | + assert_true(source.reason instanceof DOMException); | ||
| 229 | + assert_equals(source.reason, dependent.reason); | ||
| 230 | + }, `Dependent signals for ${desc} should use the same DOMException instance from the already aborted source signal ${suffix}`); | ||
| 231 | + | ||
| 232 | + test(t => { | ||
| 233 | + const controller = new controllerInterface(); | ||
| 234 | + const source = controller.signal; | ||
| 235 | + const dependent = signalInterface.any([source]); | ||
| 236 | + controller.abort(); | ||
| 237 | + assert_true(source.reason instanceof DOMException); | ||
| 238 | + assert_equals(source.reason, dependent.reason); | ||
| 239 | + }, `Dependent signals for ${desc} should use the same DOMException instance from the source signal being aborted later ${suffix}`); | ||
| 185 | 240 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -12,7 +12,7 @@ | |||
| 12 | 12 | "path": "console" | |
| 13 | 13 | }, | |
| 14 | 14 | "dom/abort": { | |
| 15 | - "commit": "d1f1ecbd52f2eab3b7fe5dc1b20b41174f1341ce", | ||
| 15 | + "commit": "0143fe244b3d622441717ce630e0114eb204f9a7", | ||
| 16 | 16 | "path": "dom/abort" | |
| 17 | 17 | }, | |
| 18 | 18 | "dom/events": { | |
| Back | FazBrowse Home | New Git URL |
0 commit comments