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 |