@@ -203,7 +203,6 @@ Event dispatches can be one of the following:
203203 user actions, or by cross-agent JS, with no involvement from JS code in the
204204 same agent. Such dispatches can't have propagated any context from some non-existing
205205 JS code that triggered them, so the listener is called with the empty context.
206- (Though see the section on fallback context below.)
207206- ** Asynchronous dispatches** , where the event originates from JS calling into
208207 some web API, but the dispatch happens at a later point. In these cases, the
209208 context should be tracked along the data flow of the operation, even across
@@ -333,106 +332,6 @@ context that the browser uses, for example, for the top-level execution of scrip
333332> [ !WARNING]
334333> To keep agents isolated, events dispatched from different agents (e.g. from a worker, or from a cross-origin iframe) will behave like events dispatched by user interaction. This also applies to events dispatched from cross-origin iframes in the same agent, to avoid exposing the fact that they're in the same agent.
335334
336- ### Fallback context ([ #107 ] ( https://github.com/tc39/proposal-async-context/issues/107 ) )
337-
338- This use of the empty context for browser-originated dispatches, however,
339- clashes with the goal of allowing "isolated" regions of code that share an event
340- loop, and being able to trace in which region an error originates. A solution to
341- this would be the ability to define fallback values for some ` AsyncContext.Variable ` s
342- when the browser runs some JavaScript code due to a browser-originated dispatch.
343-
344- ``` javascript
345- const widgetID = new AsyncContext.Variable ();
346-
347- widgetID .run (" weather-widget" , () => {
348- captureFallbackContext (widgetID, () => {
349- renderWeatherWidget ();
350- });
351- });
352- ```
353-
354- In this example, event listeners registered by ` renderWeatherWidget ` would be guaranteed
355- to always run as a consequence of some "widget": if the event is user-dispatched, then
356- it defaults to ` weather-widget ` rather than to ` widgetID ` 's default value (` undefined ` ,
357- in this case). There isn't a single global valid default value, because a page might have
358- multiple widgets that thus need different fallbacks.
359-
360- <details >
361- <summary >Expand this section to read the full example</summary >
362-
363- This complete example shows that when clicking on a button (thus, without a JavaScript cause
364- that could propagate the context), some asynchronous operations start. These operations
365- might reject, firing a ` unhandledrejection ` event on the global object.
366-
367- If there was no fallback context, the ` "click" ` event would run with ` widgetID ` unset, that
368- would thus be propagated unset to ` unhandledrejection ` as well. Thanks to ` captureFallbackContext ` ,
369- the user-dispatched ` "click" ` event will fallback to running with ` widgetID ` set to
370- ` "weather-widget" ` , which will then be propagated to ` unhandledrejection ` .
371-
372- ``` javascript
373- const widgetID = new AsyncContext.Variable ();
374-
375- widgetID .run (" weather-widget" , () => {
376- captureFallbackContext (widgetID, () => {
377- renderWeatherWidget ();
378- });
379- });
380-
381- addEventListener (" unhandledrejection" , event => {
382- console .error (` Unhandled rejection in widget "${ widgetID .get ()} "` );
383- // Handle the rejection. For example, disable the widget, or report
384- // the error to a server that can then notify the widget's developers.
385- });
386- ```
387-
388- ``` javascript
389- function renderWeatherWidget () {
390- let day = Temporal .Now .plainDate ();
391-
392- const widget = document .createElement (" div" );
393- widget .innerHTML = `
394- <button id =" prev" >Previous day</button >
395- <output >...</output >
396- <button id =" next" >Next day</button >
397- ` ;
398- document .body .appendChild (widget);
399-
400- const load = async () => {
401- const response = await fetch (` /weather/${ day} ` );
402- widget .querySelector (" output" ).textContent = await response .text ();
403- };
404-
405- widget .querySelector (" #prev" ).addEventListener (" click" , async () => {
406- day = day .subtract ({ days: 1 });
407- await load ();
408- });
409- widget .querySelector (" #next" ).addEventListener (" click" , async () => {
410- day = day .add ({ days: 1 });
411- await load ();
412- });
413-
414- load ();
415- }
416- ```
417-
418- When the user clicks on one of the buttons and the ` fetch ` it triggers fails,
419- without using ` captureFallbackContext ` the ` unhandledrejection ` event listener
420- would not know that the failure is coming from the ` weather-widget ` widget.
421-
422- Thanks to ` captureFallbackContext ` , that information is properly propagated.
423-
424- </details >
425-
426- This fallback is per-variable and not based on ` AsyncContext.Snapshot ` , to avoid
427- accidentally keeping alive unnecessary objects.
428-
429- There are still some questions about ` captureFallbackContext ` that need to be
430- answered:
431- - should it take just one variable or a list of variables?
432- - should it just be for event targets, or for all web APIs that take a callback
433- which can run when triggered from outside of JavaScript? (e.g. observers)
434- - should it be a global, or a static method of ` EventTarget ` ?
435-
436335## Status change listener callbacks
437336
438337These APIs register a callback or constructor to be invoked when some action
@@ -496,8 +395,7 @@ context to propagate:
496395 form would queue a microtask to call its ` formResetCallback ` lifecycle hook,
497396 and there would not be a causal context.
498397
499- Similarly to events, in this case lifecycle callbacks would run in the empty context, with
500- the [ fallback context mechanism] ( #fallback-context-107 ) .
398+ Similarly to events, in this case lifecycle callbacks would run in the empty context.
501399
502400## Observers
503401
@@ -510,8 +408,7 @@ Observer callbacks are not called once per observation. Instead, multiple observ
510408can be batched into one single call. This means that there is not always a single JS action
511409that causes some work that eventually triggers the observer callback; rather, there might be many.
512410
513- Given this, observer callbacks should always run with the empty context, using the same
514- [ fallback context mechanism] ( #fallback-context-107 ) as for events. This can be explained
411+ Given this, observer callbacks should always run with the empty context. This can be explained
515412by saying that, e.g. layout changes are always considered to be a browser-internal trigger, even if
516413they were caused by changes injected into the DOM or styles through JavaScript.
517414
0 commit comments