GoogleChromeLabs / tasklets

177 stars 17 forks source link

Add a way to expose failing constructors #9

Closed surma closed 7 years ago

surma commented 7 years ago

From WICG discussion: Post 1, Post 2

TL;DR:

domenic commented 7 years ago

It's pretty strange, but it's actually possible to make a function (or proxy) such that

const x = await new Y();

works, and even to make const x = await Y(); fail. Sample:

function Y() {
  if (!new.target) {
    return Promise.reject("Illegal invocation");
  }
  return new Promise(r => {
    setTimeout(() => r(createActualY()), 1000);
  });
}
domenic commented 7 years ago

I guess my concern with my above suggestion is that so far for async construction we've instructed people to use factory methods (e.g. window.createImageBitmap()) and this diverges from that precedent.

On the other hand these are pretty specialized objects, proxying from another thread, and not general web platform objects representing resources that need to be created async. So maybe it's OK for them to be special.

surma commented 7 years ago

I actually think making await new X() work would be super consistent (“Just use await for everything that involves tasklets”).

I’d totally be down with that. @bfgeek WDYT?

bfgeek commented 7 years ago

Yeah I'm not sure... the argument against this in my head is that it's one thread bounce that we can easily remove, that 99.99% of the time isn't useful.

I.e.

a = await new api.A();
a.f1();
a.f2();

(two main->bg tasks).

vs.

a = new api.A();
a.f1();
a.f2();

(only one main->bg task).

bfgeek commented 7 years ago

I.e. multiple calls which we don't await can be batched up.

surma commented 7 years ago

Developers can still batch if desired, no?

const [a1, a2, a3, a4] = 
  await Promise.all([
    new api.A(), 
    new api.A(), 
    new api.A(), 
    new api.A(),
  ]);

Another thing I realized: Exceptions are (often) used for control flow. So if the implementation of a1.f1() throws for exactly one reason, the developer will probably react to an exception with what makes sense in the context of that exception. Without being able to detect constructor exceptions in isolation, the code can throw for two reasons, for only one of which the currently implemented exception handling is appropriate.

The more I think about it, the more I like the await new, despite being a new thing™️.

surma commented 7 years ago

The polyfill now uses await new MyClass() and I think it’s more consistent. Gonna update the README and close this.

surma commented 7 years ago

For completeness’ sake:

the argument against this in my head is that it's one thread bounce

The polyfill does it in one bounce. I’m sure a native implementation can do the same ;)