Symbol.await proposal

Jamie me at thejameskyle.com
Mon Jun 22 20:13:19 UTC 2020


One of the common refactorings I do is:

let file1 = await readFile(filename1)
let file2 = await readFile(filename2)
// to
let [file1, file2] = await Promise.all([
  readFile(filename1),
  readFile(filename2),
])

I would be very confused if refactoring it in this way made my code break
because of some implicit behavior around `await` specifically.

I have seen some APIs that switch to promises when a callback argument is
not provided. Is this not a sufficient solution?

On Mon, Jun 22, 2020 at 12:22 PM James M Snell <jasnell at gmail.com> wrote:

> For many legacy code bases that are based on callbacks mechanisms like
> node.js' promisify function are required to help facilitate the transition
> from callback centric code to Promise-centric. A lot of the time, these can
> follow straightforward rules without requiring customization. However, at
> other times it is necessary for user code to provide custom implementations
> of the Promise-version of the function.
>
> In Node.js, we accomplish this by allowing a function to have a symbol
> attached whose value is an alternative function that is returned by the
> promisify function
>
> For instance,
>
>   function myFunction(foo, bar, callback) {
>     callback(null, foo, bar);
>   }
>   myFunction[util.customPromisifySymbol] = async function(foo, bar) {
>     return [foo, bar];
>   }
>
>   const { promisify } = require('util');
>   const mine = promisify(myFunction);
>   (async () => console.log(await mine('a','b')))();
>
> As a convenience built into the language, it would be nice to be able to
> short-circuit the need to call promisify with a special language-level
> Symbol used specifically for this purpose:
>
>   function myFunction(foo, bar, callback) {
>     callback(null, foo, bar);
>   }
>   myFunction[Symbol.await] = async function(foo, bar) {
>     return [foo, bar];
>   }
>
>   (async () => console.log(await myFunction('a','b')))();
>
> The idea here is that if the function being awaited has the [Symbol.await]
> property whose value is a function, then that function is called when the
> await keyword is used. That is,
>
>   myFunction('a', 'b', callback); // Invokes myFunction directly
>   await myFunction('a', 'b');  // Invokes myFunction[Symbol.await]
>
> if the Symbol.await property is not set or is not callable, then it would
> fallback to default behavior.
>
> Automatic handling of this binding should also happen but has some
> technical detail to work out:
>
>   const obj = {
>     a: 1,
>     foo() {}
>   };
>   obj.foo[Symbol.await] = async function() {
>     return this.a;
>   }
>   await obj.foo();  // Calls await obj.foo[Symbol.await] with bound this
>
> This approach would make it far easier for legacy code bases to make the
> transition to async/await syntax while maintaining legacy compat.
>
> Before writing up a formal proposal, I wanted to solicit some feedback on
> this approach to see what folks thought.
>
> - James
> _______________________________________________
> 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/20200622/6ce045c7/attachment.html>


More information about the es-discuss mailing list