Promise.finally not really final

Isiah Meadows isiahmeadows at gmail.com
Sat Sep 8 13:07:26 UTC 2018


The promise disposer pattern works basically like this:

```js
// Promise chain
function withFoo(init) {
    return getFoo().then(foo =>
        Promise.resolve()
        .then(() => init(foo))
        .finally(() => foo.destroy())
    )
}

// Async function
async function withFoo(init) {
    const foo = await getFoo()
    try {
        return await init(foo)
    } finally {
        await foo.destroy()
    }
}

// Example use
withFoo(async foo => {
    await foo.changeThings()
    return foo.getValue()
})
```

That's one big place where this is useful.

On Fri, Sep 7, 2018 at 19:18 Augusto Moura <augusto.borgesm at gmail.com>
wrote:

> Why would you destroy a node and `.then()` pause it? It doesn't make
> sense even in plain English. If the contract of the method (expected
> behavior) is to destroy the internal node, using it after is a error.
> You can easily reimplement your use case reversing the logic:
>
> ```` js
> setTimeout(() => {
>   demo.node.pause();
>   demo.destroy();
> }, 3000);
> ````
>
> Another solution is to implement a `beforeDestroy` event emitter and
> listen to it, this way is certain that the code will be executed
> always before the node is gone and after any async destroy logic:
>
> ```` js
> class Demo {
>   constructor(el) {
>     this.beforeDestroy = new EventEmitter();
>     // Using the @angular/core EventEmitter because is more "close to
> English"
>     this.node = el;
>   }
>   destroy() {
>     return new Promise(resolve => resolve())
>       .then(() => this.beforeDestroy.emit())
>       .finally(() => {
>         this.node = null;
>       });
>   }
> }
>
> const demo = new Demo(document.querySelector('video'));
>
> demo.beforeDestroy.subscribe(() => {
>   demo.node.pause();
> });
>
> setTimeout(() => {
>   demo.destroy();
> }, 3000);
> ````
>
> Anyway, the `then`, `catch` and `finally` methods mimic the serial
> try/catch/finally, simply doesn't make sense finally statements
> protecting code beyond it's try block definition, and chaining new
> `.then`s _are_ beyond the promise definition. Also, async functions
> already has finally blocks implementations in the same way as the
> current `.finally` method spec, implementing a different behaviour
> would be unnecessarily confusing.
> Em sex, 7 de set de 2018 às 16:16, Jon Ronnenberg
> <jon.ronnenberg at gmail.com> escreveu:
> >
> > I know I am late to the game and that Promise.prototype.finally is
> already in stage 4 but(!).
> >
> > It's just not very useful to have a final function when it's not the
> final function to run. If it's suppose to be for cleanup, then the current
> implementation is seriously lacking usefulness.
> >
> > Consider the following example:
> >
> > <audio
> >   class="i-am-the-element"
> >   autoplay="autoplay"
> >   controls="controls">
> >     <source type="audio/mp3" src="http:\/\/play.dogmazic.net
> \/play\/index.php?type=song&oid=22951&uid=-1&name=Black%20poetry%20-%20Aime-.mp3">
> > </audio>
> > <script>
> >   class Demo {
> >     constructor (element) {
> >       this.node = element
> >     }
> >     destroy () {
> >       return new Promise(resolve => {
> >         // do something or nothing
> >         resolve()
> >       }).finally(() => {
> >         // schedule for DOM removal
> >         this.node = null
> >       })
> >     }
> >   }
> >
> >   const demo = new Demo(document.querySelector('.i-am-the-element'))
> >
> >   setTimeout(() => {
> >     demo.destroy().then(() => {
> >    // will throw an error because finally was run before
> >       demo.node.pause()
> >     }).catch(console.error)
> >   }, 3000)
> > </script>
> >
> > One grand idea about promises is to delegate and compose asynchronous
> functions, but the current implementation can not be used to for code
> delegation.
> >
> > From the top of my head the only way to have consumer code,  tap into an
> execution process is to use callbacks which is what Promises were suppose
> to help alleviate.
> >
> > <audio
> >   class="i-am-the-element"
> >   autoplay="autoplay"
> >   controls="controls">
> >     <source type="audio/mp3" src="http:\/\/play.dogmazic.net
> \/play\/index.php?type=song&oid=22951&uid=-1&name=Black%20poetry%20-%20Aime-.mp3">
> > </audio>
> > <script>
> >   class Demo {
> >     constructor (element) {
> >       this.node = element
> >     }
> >     destroy (callback) {
> >       // do something or nothing
> >       try {
> >         callback()
> >       } finally {
> >         // schedule for DOM removal
> >         this.node = null
> >       }
> >     }
> >   }
> >
> >   const demo = new Demo(document.querySelector('.i-am-the-element'))
> >
> >   setTimeout(() => {
> >     demo.destroy(() => {
> >       demo.node.pause()
> >     })
> >   }, 3000)
> > </script>
> >
> > If at all possible, please amend to the spec before it's too late! ...
> or just drop it.
> >
> > My current use-case is that I work with PSPDFKit and can not get DOM
> access but rather schedule removal of DOM nodes via their API, but I can
> pause audio/video - just not using Promise.prototype.finally as it is
> currently envisioned.
> >
> > Regards, Jon
> >
> > PS. Tested in Firefox 63.0b3 and Safari 11.1.2
> > Here is a polyfill if you need:
> https://cdn.polyfill.io/v2/polyfill.minify.js?features=Promise.prototype.finally&flags=gated
> >
> > _______________________________________________
> > 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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180908/d3cbd171/attachment.html>


More information about the es-discuss mailing list