15:12
<tolmasky>
It is intentional that doing promise.then() removes it from the unhandled promise rejection handlers list, yeah?
15:13
<tolmasky>
(as in, literally, passing nothing in for either fulfilled or rejected)
15:42
<Ashley Claymore>
I presume the promise returned from that .then is added to the unhandled promise rejection list though?
15:47
<tolmasky>
Correct
15:48
<tolmasky>
https://runkit.com/tolmasky/promise-rejection-with-empty-then
15:57
<Kris Kowal>
Probably worth mentioning here: a better way to observe unhandled rejections would be to show promises with unhandled rejections and then hide them when they’re handled, rather than showing them only when we can prove they won’t ever be handled (finalization) or jumping to the conclusion that they won’t be handled if the handler isn’t registered in the turn of creation. It’s similarly useful to show and hide pending promises, since they can also participate in data-lock cycles. Q provides hooks for these events, for which I’d prototyped a browser debugger extension many years ago. I very much wish I’d had the capacity to carry that over the line!
15:58
<bakkot>
unhandled promise rejections in browsers are surfaced to code, not just to the debugger
15:58
<Kris Kowal>
It’s analogously interesting to visualize async iterators as pending promises that produce intermediate events. Those events have frequencies.
15:58
<bakkot>
and you certainly don't want to surface to code "here are all of the currently-unhandled promises"
15:58
<Kris Kowal>
Agreed.
16:00
<Kris Kowal>
And it’s not problematic to surface unhandled rejections after finalization. Browsers are fine there.
16:01
<tolmasky>
So, my actual use case was trying to find a non-mutative way of identifying "true" Promise objects (a Promise.isPromise analog to Array.isArray). %Promise.prototype.then%.apply(object) is almost satisfactory since it throws if the object isn't a Promise... but has side-effects if it is a Promise unfortunately. (For example, I think you can safely use %Map.prototype.get%.apply(object) to identify "true" Map objects).
16:02
<Kris Kowal>
Paging @ljharb, knower of all brand checks.
16:04
<ljharb>
tolmasky: there’s no way to do that without potentially invoking user code, so Promise.resolve(x) === x is usually the way
16:05
<ljharb>
I’d have to check, but i think that only invokes a getter for .then - so since that’s very rare to exist, it works in practice
16:05
<tolmasky>
Gotcha, We currently we just drop down to C++ in v8 to check, but wanted to confirm there's not "safe" way in JS
16:05
<ljharb>
only a “safe enough” way
16:06
<tolmasky>
To confirm in that case, as far as I can tell its possible with everything except Promise and Error (Number/Boolean/Symbol/String/Date can use C.prototype.toString and check for throw, RegExp.prototype.exec and check for throw, Map and Set can use C.prototype.has and check for throw).
16:06
<ljharb>
i suppose you could explore descriptors and see if it has no own then, and a [[Prototype]] that’s Promise.prototype, but that invokes a proxy trap
16:07
<ljharb>
Promise has the brand checks but no non-side-effect way to check it; and error sadly has no way to do the brand check, yes. Yet.
16:07
<Kris Kowal>
Ask about TypedArrays. 🍿
16:07
<ljharb>
afaik i have those covered
16:07
<Kris Kowal>
You do!
16:07
<tolmasky>
Oh, yeah? They're doable?
16:08
<ljharb>
https://npmjs.com/which-typed-array, https://npmjs.com/typed-array-length, https://npmjs.com/is-typed-array. I’d love to learn about caveats I’m unaware of.
16:08
<tolmasky>
excellent
16:21
<Jack Works>
But why can't depends on @@toStringTag? It's 2022
16:39
<tolmasky>
because anyone can change that?
16:41
<Jack Works>
Oh
17:58
<ljharb>
also anyone can fake it
17:58
<ljharb>
toStringTag is useless as anything but a debugging hint
17:58
<ljharb>
now, if it'd been a brand-checking getter…
17:58
<ljharb>
but unfortunately that idea didn't occur to me in the pre-ES6 meeting (one of my first) when I tried to get toStringTag withdrawn from ES6
18:03
<tolmasky>
Is there any reason not to add brand-checking across the board, either through X.isX on everything, or [@@brand] or something?
18:15
<bakkot>
personally I am not a fan of adding more reflection unless there is some particular reason to want it
18:33
<ljharb>
tolmasky: i'd love that, but ^ it's hard to convince folks that's compelling on its own
18:34
<tolmasky>
What is necessary for "compelling"? We've been using a non-portable node C++ addon for 5 years because this doesn't exist, does that count as a compelling reason?
18:34
<tolmasky>
Which incidentally is of course non-portable and thus won't work in, for example, bun
18:34
<tolmasky>
So we're now having to maintain a v8 C++ and a bun/zig addon...
18:43
<bakkot>
Use cases from people not on the committee, for one thing
18:44
<bakkot>
we all do all sorts of unusual things; the language should be designed for more typical users
18:47
<bakkot>
but if you have an example of the thing you need it for, that's something we could talk about
18:56
<tolmasky>
So if I leave the committee it has a higher chance of getting in ;) ?
19:41
<bakkot>
by "people not on the committee" I mean "people who are not doing extremely unusual things with the language", not literally being on the committee