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

2019-02-04 Thread David Teller
Unfortunately, turning async code (which often has components that
execute in a different thread or process) back into in sync code is
really, really hard.

What semantics would you give to this `Promise.sync()`? Can other code
be executed by the main thread while you're waiting for your promise to
be fulfilled?

* If the answer is "no", you need to also block the entire DOM and CSS
engines (both of which can call back into JavaScript) for this to work.
Or, if you're in Node, all your I/O and all your ongoing callbacks.
Needless to say, your users aren't going to be happy.

* If the answer is "yes", you are breaking the run-to-completion
guarantee of JavaScript. You may have events that are processed in the
middle of apparently synchronous execution because there's a
`Promise.sync()` hidden somewhere. That's going to break a lot of things.

For what it's worth, Firefox used to have an equivalent of
`Promise.sync()` for use in privileged code (i.e. the UI and
extensions). Experience shows that it caused insane amounts of bugs.

Cheers,
 David

P.S.: Yes, there are ways around this, if you're willing to write/use a
CPS transpiler. I've written one years ago. The results were really
powerful, but also really messy. I don't suggest heading in this direction.

On 04/02/2019 00:39, #!/JoePea 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).
> 
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


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

2019-02-03 Thread Isiah Meadows
I agree that sometimes-sync is always a nightmare, and I've
experienced this pain personally from a library API that once did
this. (I did succeed in getting it to eventually change.) I'm willing
to draw exception for things like APIs that wrap both sync and async
iterators, but those literally provide two separate entry points in
the form of `Symbol.iterator` vs `Symbol.asyncIterator` methods.

-

Isiah Meadows
cont...@isiahmeadows.com
www.isiahmeadows.com

On Mon, Feb 4, 2019 at 1:43 AM Jordan Harband  wrote:
>
> Typically, APIs that are sometimes sync and sometimes async are called 
> "zaļgo" - unpredictable, hard to maintain, hard to understand. The general 
> best practice is that a function should always be async, or always sync, but 
> never the twain shall meet.
>
> Relevant:  http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony
>
> On Sun, Feb 3, 2019 at 4:49 PM Isiah Meadows  wrote:
>>
>> 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  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.
>>> 

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

2019-02-03 Thread Jordan Harband
Typically, APIs that are sometimes sync and sometimes async are called
"z̲̗̼͙̥͚͛͑̏a̦̟̳͋̄̅ͬ̌͒͟ļ̟̉͌ͪ͌̃̚g͔͇̯̜ͬ̒́o̢̹ͧͥͪͬ" - unpredictable, hard to
maintain, hard to understand. The general best practice is that a function
should always be async, or always sync, but never the twain shall meet.

Relevant:  http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony

On Sun, Feb 3, 2019 at 4:49 PM Isiah Meadows  wrote:

> 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  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@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


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

2019-02-03 Thread Isiah Meadows
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  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@mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


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

2019-02-03 Thread #!/JoePea
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@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss