03:10
<Steve Hicks>
I think we can extend this as well. Imagine the parent is doing a fetch and creates an abort signal, then passes that same signal to the children to perform their fetches. They each setup their own fetch state otherwise, maybe logging. It’d be surprising that the parent aborting their fetch causes the child’s fetch to inherit the parent’s fetch state.
I'm not quite sure what you're saying. If you pass the same signal to the children, then aborting them is exactly what I'd expect. It should be a conscious choice which signal to pass, and reusing a signal indicates to me precisely that you want them all to abort together.
03:13
<Justin Ridgewell>
I expect the children to abort, not for the cleanup code in the children to assume the signaling event’s context.
03:15
<Steve Hicks>
Gotcha, I think I misunderstood "sets up their own fetch state". You were saying that they might add some of their own async vars as well, and that it should be encapsulated to the child rather than flowing through from the parent. I agree.
03:16
<Justin Ridgewell>
Yes, rereading it now I didn’t word it well.
04:29
<Steve Hicks>

Another example where encapsulated (defualt flow-around) approach makes sense is to behave like React's <Context.Provider>. That API is designed to avoid "prop drilling", where an outer JSX component needs to pass data to an inner JSX component, but due to JSX's design, this ends up requiring every component in between to accept and pass along that same data. The generally accepted solution is to put a <Context> element around the outside, and then it can be accessed directly by any descendent without adding arguments everywhere in between. If, for some reason, there were an additional provider for the same context variable, it would override the previous one, but only for the current scope - so it's clean. It would be very susprising if changes to this context in a child scope ended up affecting other sibling subcomponents.

In general, this use case of "implicit parameter propagation without needing to virally change the signatures in between" is relevant both in JSX but also in ordinary JS, and it basically always wants the bind-around approach.

09:27
<Jia Li>
Hello, I am Jia Li, the maintainer of the Zone.js, thank you for having me here.
12:49
<littledan>
Hello, I am Jia Li, the maintainer of the Zone.js, thank you for having me here.
Thank you so much for joining! We were wondering, could you tell us about how Zone.js arrived at its current policy of which fallbacks to zone-wrap and how? I have heard that this changed over time to fix bugs. We are trying to work out the analogous policy for AsyncContext.
12:53
<littledan>
One particular example we have been thinking about is, what zone should an event run in, when it is triggered by JS? I guess Zone.js runs it in the zone where the event was registered, but we are thinking about running it in the zone which triggered the event.
13:46
<Jia Li>

littledan:
Yeah, I remembered this issue have been discussed in the earlier stage of zone.js development, the policy of Zone.js is the callback should run in the same context(zone) when the task is scheduled.

  1. for macrotask, such as setTimeout(callback), the setTimeout call schedule the async operation, so the callback should be in the same context(zone) with the setTimeout call
zone1.run(() => {
  setTimeout(() => {
    console.log(Zone.current.name); // should be zone1
  }, 0);
});
  1. about eventTask such as button.addEventListener('click', handler);, we considered the schedule process is the addEventListener call instead of the dispatchEvent call.
zone1.run(() => {
  button.addEventListener('click', () => {
     console.log(Zone.current.name) // should be zone1;
  });

  zone2.run(() => {
    button.dispatchEvent(clickEvent);
  });
});
  1. for microtask such as Promise, the schedule process is when promise.then is called.
let p = null;
zone1.run(() => {
  p = new Promise(...);
});
zone2.run(() => {
  p.then(() => {
    console.log(Zone.current); // will be zone2
  })
});
13:47
<littledan>
Jia Li: What kind of feedback have you gotten over time about this policy? Do people ever complain that it gives them the wrong results?
13:56
<Jia Li>

About eventTask, some people asks the question why the zone is not the zone when the event triggered which is confuse in some cases, but in Angular, event task basically always run in the same zone, so there are no big difference about using the register zone or the trigger zone(they are the same in the 99% of the use cases).

And I think the event trigger such as dispatchEvent is a synchronized operation, so depends on should we consider eventTask as an async operation, if it is , I think using the register zone is reasonable, if not, zone.js should leave the eventTask alone and not wrap it at all.

14:29
<Stephen Belanger>

The exit is the end of the scope function. It applies scopes in exactly the same way. It just does it implicitly at the runtime level. And yes, there most certainly is a way to know when execution ends: any time the runtime would become idle and/or transition to microtask processing it knows it has reached the end of the current selection of synchronous code. At that point you end that context.

However, you don't actually need to know when an end occurs if all execution descends from a root at the beginning of execution as then the start of any execution would be propagating and therefore swapping out the context value anyway, so clearing it at the end actually becomes unnecessary as it would be immediately followed by a change anyway. There's actually been mathematical proofs of this for the .NET implementation.

14:38
<littledan>

About eventTask, some people asks the question why the zone is not the zone when the event triggered which is confuse in some cases, but in Angular, event task basically always run in the same zone, so there are no big difference about using the register zone or the trigger zone(they are the same in the 99% of the use cases).

And I think the event trigger such as dispatchEvent is a synchronized operation, so depends on should we consider eventTask as an async operation, if it is , I think using the register zone is reasonable, if not, zone.js should leave the eventTask alone and not wrap it at all.

Not wrapping at all seems kinda incomplete as well; sometimes no JS was on the stack when the event was triggered. I was imagining that the registration-time zone should be used for some of those cases (e.g., onload)
14:39
<littledan>
Even for clicking, sometimes you dispatchEvent, but usually you actually just click, in which case you don't have anything to go on besides the registration zone
14:40
<littledan>
so maybe the "triggering zone" should be used when it exists, otherwise you fall back to the registration-time zone
19:22
<Justin Ridgewell>

The exit is the end of the scope function. It applies scopes in exactly the same way. It just does it implicitly at the runtime level. And yes, there most certainly is a way to know when execution ends: any time the runtime would become idle and/or transition to microtask processing it knows it has reached the end of the current selection of synchronous code. At that point you end that context.

However, you don't actually need to know when an end occurs if all execution descends from a root at the beginning of execution as then the start of any execution would be propagating and therefore swapping out the context value anyway, so clearing it at the end actually becomes unnecessary as it would be immediately followed by a change anyway. There's actually been mathematical proofs of this for the .NET implementation.

The exit is the end of the scope function

Which means there’s a leak until the end of the function. https://gist.github.com/jridgewell/4aa2d6458f41d4574d6aeb580dc80d5d
19:24
<Justin Ridgewell>
And yes, there most certainly is a way to know when execution ends: any time the runtime would become idle and/or transition to microtask processing it knows it has reached the end of the current selection of synchronous code.

How do you propose expsoing this API to libraries?
20:01
<Justin Ridgewell>
However, you don't actually need to know when an end occurs if all execution descends from a root at the beginning of execution as then the start of any execution would be propagating and therefore swapping out the context value anyway

This doesn’t fully remove the need for the above end of task detection, becuase the last object placed there can’t be freed until the event loops replaces the context. It also means that Jobs would place an empty context when they return, which is OK I guess.
23:24
<Jia Li>
so maybe the "triggering zone" should be used when it exists, otherwise you fall back to the registration-time zone

So there are two cases.

  1. User registered the click event handler in zone1, and user click the button with mouse, the click behavior happens in a noop zone (the default zone), and the handler should run in the registered zone.
  2. User registered the click event handler in zone1, and user trigger the zone programmatically with something like dispatchEvent in zone2, so in this case, it is confusing that which zone should the handler run into, from the zone.js unified policy perspective, it should be zone1, otherwise in the 1st usecase, the handler should run in the noop zone, but some user may want to see zone2 in some scenario.

I still belive the current policy (run callback in the register zone) make more senses, and maybe in some cases let use can also access both the register zone and the trigger zone will be better.

23:41
<Justin Ridgewell>
zone.js unified policy perspective

Is this documented somewhere?