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 <isiahmead...@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 > m...@isiahmeadows.com > www.isiahmeadows.com > > > On Fri, Jul 20, 2018 at 12:04 AM, Bob Myers <r...@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 <ljh...@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 <isiahmead...@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 > >>> m...@isiahmeadows.com > >>> www.isiahmeadows.com > >>> _______________________________________________ > >>> es-discuss mailing list > >>> es-discuss@mozilla.org > >>> https://mail.mozilla.org/listinfo/es-discuss > >> > >> > >> _______________________________________________ > >> es-discuss mailing list > >> es-discuss@mozilla.org > >> https://mail.mozilla.org/listinfo/es-discuss > _______________________________________________ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > -- Augusto Moura
_______________________________________________ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss