returning non-Promise values from async functions and running them synchronously (or Promise.sync() idea)

Isiah Meadows isiahmeadows at gmail.com
Mon Feb 4 00:49:19 UTC 2019


You could move the async part into a helper function and call that from a
sync function you instead expose. I've used this trick more than once, and
although it is a bit of boilerplate, it works well enough.
On Sun, Feb 3, 2019 at 18:40 #!/JoePea <joe at trusktr.io> wrote:

> I often find myself enjoying async functions until the time comes when I
> don't want to await anything, and I want the call stack to be sync (i.e. I
> don't want to defer if I don't have to).
>
> But, async functions always return a Promise. So I find my self converting
> my async functions back into normal functions so that I can return
> non-Promise values, this way the caller can wait only if I return a
> promise, otherwise continue synchronously.
>
> Here's an example function in one of my classes:
>
> ```js
>             initWebGL() {
>                 if (this.__glLoading) return false
>                 this.__glLoading = true
>
>                 // order of the if-else matters!
>                 if (this.__glUnloading) return
> Promise.resolve().then(A.bind(this))
>                 else if (this.__glLoaded) return false
>
>                 A.call(this)
>
>                 function A() {
>                     // ... load stuff (omitted for brevity) ...
>                 }
>
>                 return true
>             }
> ```
>
> then the caller (f.e. a subclass) only needs to wait when a promise is
> returned:
>
> ```js
>         initWebGL() {
>             const superResult = super.initWebGL()
>             if (superResult instanceof Promise) return
> superResult.then(A.bind(this))
>             if (!superResult) return false
>
>             A.call(this)
>
>             function A() {
>                     // ... subclass loads stuff (omitted for brevity) ...
>             }
>
>             return true
>         }
> ```
>
> This is just one example, but in general I find many cases where I want to
> run synchronously most of the time, and only sometimes have to defer
> (whether by choice or not).
>
> So I am losing out on the nice `await` syntax just because I can not do
> what I want to do with `async`/`await`.
>
> What if async functions could have some way to continue synchronously, and
> return non-Promise values?
>
> Or, what if we could have some sort of Promise API that would cause any
> callers to synchronously away, like in the following example, so that the
> change is not a breaking change, and async functions would still return
> Promises but the Promise could perhaps continue synchronously:
>
> ```js
> async function example() {
>   return Promise.sync()
> }
> ```
>
> Then, in a caller, there would be no microtask deferral:
>
> ```js
> async function test() {
>   await example()
>   console.log('one')
>   // implicit return is a Promise.sync() here.
> }
>
> function main() {
>   test()
>   console.log('two')
> }
> ```
>
> The output in this case would be:
>
> ```
> "one"
> "two"
> ```
>
> Note that in that example, we are _sure_ that `two` is logged after `one`
> because those async functions only ever use `Promise.sync()`.
>
> It would be good practice to use `await` regardless, because one may not
> know if the async function they are calling will return a
> non-`Promise.sync` value. So the `main` function is better written as
>
> ```js
> async function main() {
>   await test()
>   console.log('two')
> }
> ```
>
> In this case, everything still happens synchronously, but if the author of
> `example()` changes the implementation to return a non-sync Promise, then
> things will still run in the expected order. F.e.
>
> ```js
> async function example() {
>   await fetch(...)
> }
> ```
>
> I keep finding scenarios where I want to avoid async unless I need async,
> but then I lose the convenient async/await syntax.
> _______________________________________________
> 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/20190203/54c3fe17/attachment-0001.html>


More information about the es-discuss mailing list