00:50
<littledan>
I think if we want this, and we also want promise.then() with no arguments to not catch the current snapshot, we would need to add a new slot to promises
I don't have a strong intuition for what would be the "best" semantics in this case, but I think then() is the kind of case where people who do such a strange thing should "take what they get" rather than us adding complexity for that particular case. If we didn't add a new slot to promises, what semantics would fall out/be possible?
05:34
<ljharb>
why is writing .then() a strange thing?
07:03
<nicolo-ribaudo>
Because usually you pass a function to it
09:54
<Andreu Botella>
you have the same issue when passing a fulfillment handler without a rejection handler to .then(), I think
19:17
<Justin Ridgewell>

do you expect the unhandledrejection listener to be always called with the same snapshot?

Yes, I think both semantics (promise-init and reject-call) should have the same snapshot here

19:19
<Justin Ridgewell>

If we didn't add a new slot to promises, what semantics would fall out/be possible?

I think capturing the same context is trivially done? Like, literally no work is required, it just falls out of the current specification (once we fix the bug). This is the same for both init and call time semantics.

19:20
<littledan>
you have the same issue when passing a fulfillment handler without a rejection handler to .then(), I think
Sorry, could you summarize what the issue is and what the semantics would be if you didn't do anything special?
19:21
<littledan>
probably if you give an example of a usage of .then(cb) it'll feel less obscure to me
19:21
<littledan>

If we didn't add a new slot to promises, what semantics would fall out/be possible?

I think capturing the same context is trivially done? Like, literally no work is required, it just falls out of the current specification (once we fix the bug). This is the same for both init and call time semantics.

This is what I expected; are we anticipating any problems with fixing the bug? I mean, I thought the fix did not lead to a snapshot associated with the promise
19:23
<Justin Ridgewell>
I don't anticipate any issues. The snapshot must be restored to the global state before calling the unhandledrejection handler, and the promise will be rejected within that tick, so it should just get the context from the global state like everything else.
21:02
<Andreu Botella>
I'm not sure I fully understand all of the semantics that we want for unhandledrejection
21:05
<Andreu Botella>
my understanding was that the async context in which HostPromiseRejectionTracker(promise, "reject") should be called is the context in which the rejection of this promise was ultimately caused, even if that was in a different promise which caused the current promise to reject via reactions
21:06
<Andreu Botella>
const unhandledPromise1 = asyncVar.run("foo", () => Promise.reject());
const unhandledPromise2 = unhandledPromise1.then(() => console.log("Not reached"));
21:06
<Andreu Botella>
so that when unhandledrejection is fired for unhandledPromise2, asyncVar.get() === "foo"
21:07
<Andreu Botella>
if that is the expected behavior, then that should also hold even if the unhandledrejection for unhandledPromise1 has already been called by the time unhandledPromise2 is created
21:08
<Andreu Botella>
and therefore the "foo" snapshot must be stored somewhere
21:09
<Andreu Botella>
currently that snapshot isn't stored anywhere after unhandledPromise1 because there are no promise jobs created inside the .run callback
21:17
<Andreu Botella>
but maybe calling Promise.p.then should always use the current snapshot at the time of the call, even for unhandledrejection
21:17
<Justin Ridgewell>

so that when unhandledrejection is fired for unhandledPromise2, asyncVar.get() === "foo"

This is incorrect. The reaction that creates p2 has escaped the foo context, so it will only see undefined. Even with init-time unhandledrejection semantics, that wouldn't change. If we eliminate the promise reaction slot and instead store on the promise, p2 would see foo.

21:18
<Justin Ridgewell>
(I'm using p1 and p2 because unhandledPromise1 is too much)
21:19
<Justin Ridgewell>

if that is the expected behavior, then that should also hold even if the unhandledrejection for unhandledPromise1 has already been called by the time unhandledPromise2 is created

unhandledrejection execution is special if we use init-time rejection semantics, because it will copy the promise's snapshot slot into global storage before executing

21:21
<Andreu Botella>
I am not really familiar with V8's promise hooks, and since much of this unhandledrejection has been framed in those terms, I should probably familiarize myself with them first
21:21
<Justin Ridgewell>
If we use call-time semantics, then unhandledrejection isn't any different then rejected.then(() => handleRejection(…)), where handledRejection returns another rejected promise/throw completion
21:21
<Andreu Botella>
because I think otherwise there's a lot of semantics that I'm missing
21:22
<Justin Ridgewell>
Do you mean async hooks?
21:22
<Andreu Botella>
either, I guess
21:23
<Andreu Botella>
but I guess I had been assuming some behavior was expected when it wasn't