Augusto Moura (2018-07-20T16:15:24.000Z)
I think what Jordan means, it's that the deferred has it use case, but
probably we don't want it in Javascript native library. There's a lot of
mature libraries implementing deferred wrappers and most of them are
Promise like compatible, and even if you cannot use libraries or don't want
to, you can easily implement a Promise extension and use it yourself.

Interesting enough, I got a really weird case (reads contraintuitive, I'm
pretty sure the semantics of the error are right) extending the Promise
class to exemplify a simple Deferred implementation, the code:

``` js
class Deferred extends Promise {
  constructor(factory) {
    super((resolve, reject) => {
      Object.assign(this, { reject, resolve });
      factory(resolve, reject);
    });
  }
}

const d = new Deferred(() => {});
```
The problem is the usage of `this` before calling the super constructor
(even when the using in the super call itself). I wonder with it there are
any ways of capturing the super constructor arguments in a Base class using
class syntax. You probably can get the arguments in a old "function class"
syntax (can be done weakmaps too). We can probably start ~yet~ another
thread on Promises, about this problem (supposing there's no way of passing
`this` to the promise factory).

Em sex, 20 de jul de 2018 às 03:03, Isiah Meadows <isiahmeadows at gmail.com>
escreveu:

> First, I do get that not all uses of deferred-like objects really
> merit the need for a deferred. For example, [here][1], I saved the
> resolver and pulled the state out from the main closure to make the
> state easier to follow. You could argue a deferred isn't really
> necessary since I only care about the `resolve` function, and nothing
> else. It's also pretty trivial to factor it back into a closure where
> it was originally.
>
> [1]:
> https://github.com/isiahmeadows/thallium/blob/master/lib/core/tests.js#L337-L428
>
> But it's when external forces control them indirectly through a state
> machine or similar, that's when it becomes necessary. I have some
> closed-source uses, but here's a couple concrete examples I have in
> OSS code:
>
> 1. Here, I have to treat it like a continuation because I have to wait
> for an IPC protocol sequence to complete before it resolves/rejects:
>
> https://github.com/isiahmeadows/invoke-parallel/blob/master/lib/api.js#L144-L147
> 2. Here, I have to treat it like a continuation because it's placed
> into a job queue driven by mainly the completion of child processes:
>
> https://github.com/isiahmeadows/website/blob/570db369cfca2b8a4a525be4e4621c854788b4d0/scripts/exec-limit.js#L71-L73
>
> There is literally no other way to handle these beyond using a fake
> deferred, thanks to the fact they aren't resolved directly in response
> to any external forces, but indirectly as the result of a state
> machine transition or similar. I can't even pass them around where I
> need them, because there's a giant process wall I have to cross each
> time. And it's this kind of use case that drove me to request this.
> The resolver functions get in my way, they take up more memory than
> necessary, and I've found myself occasionally adding separate arrays
> of resolver/rejector functions so I can also avoid the indirection of
> calling them.
>
> In general, I don't like using deferreds if I can help it - it's
> nothing but boilerplate for the common case. Here's what I usually
> prefer in order, provided I can help it:
>
> - The return value itself.
> - `async`/`await`
> - `Promise.prototype.finally` or some similar abstraction.
> - `Promise.prototype.then`/`Promise.prototype.catch`
> - `Promise.resolve`/`Promise.reject`
> - `Promise.try` or some similar abstraction.
> - `Promise.all([...])`/`Promise.race([...])
> - `new Promise(...)` using the callbacks directly.
> - `new Promise(...)`, converting the result to a pseudo-deferred.
>
> I'm not asking about this because I *enjoy* deferreds - they're
> nothing but useless boilerplate for the vast majority of use cases. In
> fact, I actively try to avoid it most of the time. I'm just asking for
> an escape hatch in case the *simple* stuff becomes boilerplate, one
> mirroring how the spec already deals with those complex scenarios.
> Very few things hit that breaking point when the callbacks become
> boilerplate, but low-level async code requiring a dedicated state
> machine driven by both calls and external effects has a habit of
> hitting that very quickly.
>
> -----
>
> Isiah Meadows
> me at isiahmeadows.com
> www.isiahmeadows.com
>
>
> On Fri, Jul 20, 2018 at 12:04 AM, Bob Myers <rtm at gol.com> wrote:
> > I've used this pattern exactly twice in the large-scale app I'm working
> on
> > now.
> > One of those I was able to eliminate after I thought harder about the
> > problem.
> > The other I eventually replaced with the following kind of pattern:
> >
> > ```
> > function createPromise(resolver, rejector) {
> >   return new Promise((resolve, reject) {
> >     resolver.then(resolve);
> >     rejector.then(reject);
> >     });
> > }
> > ```
> >
> > Obviously the way this works it that to create a promise "controllable"
> from
> > "the outside",
> > you create your own resolver and rejector promises to pass to
> > `createPromise`,
> > such that they trigger when you need them to.
> > To put it a different way, instead of getting back and passing around
> > deferred-like objects,
> > which seems to be a massive anti-pattern to me,
> > the client creates their own promise-controlling promises designed to
> > trigger at the right time.
> >
> > Bob
> >
> > On Fri, Jul 20, 2018 at 9:07 AM Jordan Harband <ljharb at gmail.com> wrote:
> >>
> >> I don't think the Deferred pattern is a good primitive to have in the
> >> language, and it's a pretty trivial primitive to write yourself if you
> need
> >> it.
> >>
> >> On Thu, Jul 19, 2018 at 6:13 PM, Isiah Meadows <isiahmeadows at gmail.com>
> >> wrote:
> >>>
> >>> Sometimes, it's *very* convenient to have those `resolve`/`reject`
> >>> functions as separate functions. However, when logic gets complex
> >>> enough and you need to send them elsewhere, save a continuation, etc.,
> >>> it'd be much more convenient to just have a capability object exposed
> >>> more directly rather than go through the overhead and boilerplate of
> >>> going through the constructor with all its callback stuff and
> >>> everything.
> >>>
> >>> It's surprisingly not as uncommon as you'd expect for me to do this:
> >>>
> >>> ```js
> >>> let resolve, reject
> >>> let promise = new Promise((res, rej) => {
> >>>     resolve = res
> >>>     reject = rej
> >>> })
> >>> ```
> >>>
> >>> But doing this repeatedly gets *old*, especially when you've had to
> >>> write it several dozen times already. And it comes up frequently when
> >>> you're writing lower-level async utilities that require saving promise
> >>> state and resolving it in a way that's decoupled from the promise
> >>> itself.
> >>>
> >>> -----
> >>>
> >>> So here's what I propose:
> >>>
> >>> - `Promise.newCapability()` - This basically returns the result of
> >>> [this][1], just wrapped in a suitable object whose prototype is
> >>> %PromiseCapabilityPrototype% (internal, no direct constructor). It's
> >>> subclass-safe, so you can do it with subclasses as appropriate, too.
> >>> - `capability.resolve(value)` - This invokes the implicit resolver
> >>> created for it, spec'd as [[Resolve]].
> >>> - `capability.reject(value)` - This invokes the implicit rejector
> >>> created for it, spec'd as [[Reject]].
> >>> - `capability.promise` - This returns the newly created promise.
> >>>
> >>> Yes, this is effectively a deferred API, but revealing constructors
> >>> are a bit too rigid and wasteful for some use cases.
> >>>
> >>> [1]: https://tc39.github.io/ecma262/#sec-newpromisecapability
> >>>
> >>> -----
> >>>
> >>> Isiah Meadows
> >>> me at isiahmeadows.com
> >>> www.isiahmeadows.com
> >>> _______________________________________________
> >>> es-discuss mailing list
> >>> es-discuss at mozilla.org
> >>> https://mail.mozilla.org/listinfo/es-discuss
> >>
> >>
> >> _______________________________________________
> >> es-discuss mailing list
> >> es-discuss at mozilla.org
> >> https://mail.mozilla.org/listinfo/es-discuss
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
-- 
Augusto Moura
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180720/27cb0076/attachment-0001.html>
augusto.borgesm at gmail.com (2018-07-20T20:30:50.461Z)
I think what Jordan means, it's that the deferred has it use case, but
probably we don't want it in Javascript native library. There's a lot of
mature libraries implementing deferred wrappers and most of them are
Promise like compatible, and even if you cannot use libraries or don't want
to, you can easily implement a Promise extension and use it yourself.

Interesting enough, I got a really weird case (reads contraintuitive, I'm
pretty sure the semantics of the error are right) extending the Promise
class to exemplify a simple Deferred implementation, the code:

``` js
class Deferred extends Promise {
  constructor(factory) {
    super((resolve, reject) => {
      Object.assign(this, { reject, resolve });
      factory(resolve, reject);
    });
  }
}

const d = new Deferred(() => {});
```
The problem is the usage of `this` before calling the super constructor
(even when the using in the super call itself). I wonder with it there are
any ways of capturing the super constructor arguments in a Base class using
class syntax. You probably can get the arguments in a old "function class"
syntax (can be done weakmaps too). We can probably start ~yet~ another
thread on Promises, about this problem (supposing there's no way of passing
`this` to the promise factory).