Re: Promises: unhandled rejections and finally()

2020-03-28 Thread Jordan Harband
It does pass through the fulfillment status - but it does that by adding
both an onFulfilled and an onRejected handler, so it does affect the
"unhandled rejection" hook.

On Sat, Mar 28, 2020 at 7:23 PM Felipe Gasper 
wrote:

> Hi Logan,
>
> Thank you .. that makes sense. I’m not sure why now but I had in mind that
> finally() creates a “passthrough” promise that doesn’t affect its parent
> promise’s resolved/rejected status.
>
> Cheers,
> -Felipe
>
> On Mar 28, 2020, at 21:40, Logan Smyth  wrote:
>
> 
> > Could someone point me to something that would help me to understand the
> logic here? It looks like the first finally() is getting a “free pass”
> while only the 2nd and subsequent ones trigger their own
> unhandled-rejection warnings.
>
> I think the best place to start in understanding this would be to step
> back and make sure you understand what it is that triggers these errors.
> Node triggers these errors when a promise object has been rejected but has
> no handlers to do respond to the rejection. I forget exactly what point
> Node checks for handlers these days, if that point is at the end of the job
> execution or on GC of promises now or what but that's not important for
> this case.
>
> Let's look at your example. I'm also simplifying it to
> ```
> var p = Promise.reject(789);
> var one = p.finally(() => {});
> var two = p.finally(() => {});
> var three = p.finally(() => {});
> ```
>
> 1)
> ```
> var p = Promise.reject(789);
> ```
> There is only one promise here, `p`, and it has no handlers ever attached
> to it so there is nothing to handle the rejection error, hence the single
> uncaught rejection error.
>
> 2)
> ```
> var p = Promise.reject(789);
> var one = p.finally(() => {});
> ```
> There are 2 promises here, `p`, which has one handler (the `finally` that
> will take the rejection of `p` and in turn reject `one`) and `one`, which
> has no handlers attached, so you again get a single uncaught rejection. It
> as not that the first "finally" gets a "free pass", it is that rejections
> from `p` are no longer uncaught, but you have added a new promise that is
> uncaught, so the overall number of uncaught rejections does not change.
>
> 3)
> ```
> var p = Promise.reject(789);
> var one = p.finally(() => {});
> var two = p.finally(() => {});
> ```
> Hopefully you can see where this is going. `p` now has 2 handlers attached
> so its rejection isn't uncaught, but now both `one` and `two` have no
> handlers, so _both_ will trigger an uncaught rejection error.
>
> 4)
> ```
> var p = Promise.reject(789);
> var one = p.finally(() => {});
> var two = p.finally(() => {});
> var three = p.finally(() => {});
> ```
> And finally now we have `one`, `two` and `three` all with no handlers
> attached, so you will get three uncaught rejection errors.
>
> Hope that helps!
>
>
> On Sun, Mar 29, 2020 at 9:03 AM Felipe Gasper 
> wrote:
>
>> Hello,
>>
>> In node 12 as well as the latest Chrome and FF (all on macOS) I see the
>> following:
>>
>> -
>> var y,n; var p = new Promise( (yy,nn) => { y=yy; n=nn } ); n(789);
>> ==> produces 1 unhandled-rejection warning
>>
>> var y,n; var p = new Promise( (yy,nn) => { y=yy; n=nn } ); p.finally( ()
>> => {} ); n(789);
>> ==> produces 1 unhandled-rejection warning
>>
>> var y,n; var p = new Promise( (yy,nn) => { y=yy; n=nn } ); p.finally( ()
>> => {} ); p.finally( () => {} ); n(789);
>> ==> produces 2 unhandled-rejection warnings
>>
>> var y,n; var p = new Promise( (yy,nn) => { y=yy; n=nn } ); p.finally( ()
>> => {} ); p.finally( () => {} ); p.finally( () => {} ); n(789);
>> ==> produces 3 unhandled-rejection warnings
>>
>> -
>>
>> Could someone point me to something that would help me to understand the
>> logic here? It looks like the first finally() is getting a “free pass”
>> while only the 2nd and subsequent ones trigger their own
>> unhandled-rejection warnings.
>>
>> Thank you!
>>
>> cheers,
>> -Felipe Gasper
>> ___
>> 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: Promises: unhandled rejections and finally()

2020-03-28 Thread Felipe Gasper
Hi Logan,

Thank you .. that makes sense. I’m not sure why now but I had in mind that 
finally() creates a “passthrough” promise that doesn’t affect its parent 
promise’s resolved/rejected status.

Cheers,
-Felipe

> On Mar 28, 2020, at 21:40, Logan Smyth  wrote:
> 
> 
> > Could someone point me to something that would help me to understand the 
> > logic here? It looks like the first finally() is getting a “free pass” 
> > while only the 2nd and subsequent ones trigger their own 
> > unhandled-rejection warnings.
> 
> I think the best place to start in understanding this would be to step back 
> and make sure you understand what it is that triggers these errors. Node 
> triggers these errors when a promise object has been rejected but has no 
> handlers to do respond to the rejection. I forget exactly what point Node 
> checks for handlers these days, if that point is at the end of the job 
> execution or on GC of promises now or what but that's not important for this 
> case. 
> 
> Let's look at your example. I'm also simplifying it to
> ```
> var p = Promise.reject(789); 
> var one = p.finally(() => {}); 
> var two = p.finally(() => {}); 
> var three = p.finally(() => {});
> ```
> 
> 1)
> ```
> var p = Promise.reject(789);
> ```
> There is only one promise here, `p`, and it has no handlers ever attached to 
> it so there is nothing to handle the rejection error, hence the single 
> uncaught rejection error.
> 
> 2) 
> ```
> var p = Promise.reject(789); 
> var one = p.finally(() => {});
> ```
> There are 2 promises here, `p`, which has one handler (the `finally` that 
> will take the rejection of `p` and in turn reject `one`) and `one`, which has 
> no handlers attached, so you again get a single uncaught rejection. It as not 
> that the first "finally" gets a "free pass", it is that rejections from `p` 
> are no longer uncaught, but you have added a new promise that is uncaught, so 
> the overall number of uncaught rejections does not change.
> 
> 3)
> ```
> var p = Promise.reject(789); 
> var one = p.finally(() => {}); 
> var two = p.finally(() => {});
> ```
> Hopefully you can see where this is going. `p` now has 2 handlers attached so 
> its rejection isn't uncaught, but now both `one` and `two` have no handlers, 
> so _both_ will trigger an uncaught rejection error.
> 
> 4)
> ```
> var p = Promise.reject(789); 
> var one = p.finally(() => {}); 
> var two = p.finally(() => {});
> var three = p.finally(() => {});
> ```
> And finally now we have `one`, `two` and `three` all with no handlers 
> attached, so you will get three uncaught rejection errors.
> 
> Hope that helps!
> 
> 
>> On Sun, Mar 29, 2020 at 9:03 AM Felipe Gasper  
>> wrote:
>> Hello,
>> 
>> In node 12 as well as the latest Chrome and FF (all on macOS) I see the 
>> following:
>> 
>> -
>> var y,n; var p = new Promise( (yy,nn) => { y=yy; n=nn } ); n(789);
>> ==> produces 1 unhandled-rejection warning
>> 
>> var y,n; var p = new Promise( (yy,nn) => { y=yy; n=nn } ); p.finally( () => 
>> {} ); n(789);
>> ==> produces 1 unhandled-rejection warning
>> 
>> var y,n; var p = new Promise( (yy,nn) => { y=yy; n=nn } ); p.finally( () => 
>> {} ); p.finally( () => {} ); n(789);
>> ==> produces 2 unhandled-rejection warnings
>> 
>> var y,n; var p = new Promise( (yy,nn) => { y=yy; n=nn } ); p.finally( () => 
>> {} ); p.finally( () => {} ); p.finally( () => {} ); n(789);
>> ==> produces 3 unhandled-rejection warnings
>> 
>> -
>> 
>> Could someone point me to something that would help me to understand the 
>> logic here? It looks like the first finally() is getting a “free pass” while 
>> only the 2nd and subsequent ones trigger their own unhandled-rejection 
>> warnings.
>> 
>> Thank you!
>> 
>> cheers,
>> -Felipe Gasper
>> ___
>> 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: Promises: unhandled rejections and finally()

2020-03-28 Thread Logan Smyth
> Could someone point me to something that would help me to understand the
logic here? It looks like the first finally() is getting a “free pass”
while only the 2nd and subsequent ones trigger their own
unhandled-rejection warnings.

I think the best place to start in understanding this would be to step back
and make sure you understand what it is that triggers these errors. Node
triggers these errors when a promise object has been rejected but has no
handlers to do respond to the rejection. I forget exactly what point Node
checks for handlers these days, if that point is at the end of the job
execution or on GC of promises now or what but that's not important for
this case.

Let's look at your example. I'm also simplifying it to
```
var p = Promise.reject(789);
var one = p.finally(() => {});
var two = p.finally(() => {});
var three = p.finally(() => {});
```

1)
```
var p = Promise.reject(789);
```
There is only one promise here, `p`, and it has no handlers ever attached
to it so there is nothing to handle the rejection error, hence the single
uncaught rejection error.

2)
```
var p = Promise.reject(789);
var one = p.finally(() => {});
```
There are 2 promises here, `p`, which has one handler (the `finally` that
will take the rejection of `p` and in turn reject `one`) and `one`, which
has no handlers attached, so you again get a single uncaught rejection. It
as not that the first "finally" gets a "free pass", it is that rejections
from `p` are no longer uncaught, but you have added a new promise that is
uncaught, so the overall number of uncaught rejections does not change.

3)
```
var p = Promise.reject(789);
var one = p.finally(() => {});
var two = p.finally(() => {});
```
Hopefully you can see where this is going. `p` now has 2 handlers attached
so its rejection isn't uncaught, but now both `one` and `two` have no
handlers, so _both_ will trigger an uncaught rejection error.

4)
```
var p = Promise.reject(789);
var one = p.finally(() => {});
var two = p.finally(() => {});
var three = p.finally(() => {});
```
And finally now we have `one`, `two` and `three` all with no handlers
attached, so you will get three uncaught rejection errors.

Hope that helps!


On Sun, Mar 29, 2020 at 9:03 AM Felipe Gasper 
wrote:

> Hello,
>
> In node 12 as well as the latest Chrome and FF (all on macOS) I see the
> following:
>
> -
> var y,n; var p = new Promise( (yy,nn) => { y=yy; n=nn } ); n(789);
> ==> produces 1 unhandled-rejection warning
>
> var y,n; var p = new Promise( (yy,nn) => { y=yy; n=nn } ); p.finally( ()
> => {} ); n(789);
> ==> produces 1 unhandled-rejection warning
>
> var y,n; var p = new Promise( (yy,nn) => { y=yy; n=nn } ); p.finally( ()
> => {} ); p.finally( () => {} ); n(789);
> ==> produces 2 unhandled-rejection warnings
>
> var y,n; var p = new Promise( (yy,nn) => { y=yy; n=nn } ); p.finally( ()
> => {} ); p.finally( () => {} ); p.finally( () => {} ); n(789);
> ==> produces 3 unhandled-rejection warnings
>
> -
>
> Could someone point me to something that would help me to understand the
> logic here? It looks like the first finally() is getting a “free pass”
> while only the 2nd and subsequent ones trigger their own
> unhandled-rejection warnings.
>
> Thank you!
>
> cheers,
> -Felipe Gasper
> ___
> 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


Promises: unhandled rejections and finally()

2020-03-28 Thread Felipe Gasper
Hello,

In node 12 as well as the latest Chrome and FF (all on macOS) I see the 
following:

-
var y,n; var p = new Promise( (yy,nn) => { y=yy; n=nn } ); n(789);
==> produces 1 unhandled-rejection warning

var y,n; var p = new Promise( (yy,nn) => { y=yy; n=nn } ); p.finally( () => {} 
); n(789);
==> produces 1 unhandled-rejection warning

var y,n; var p = new Promise( (yy,nn) => { y=yy; n=nn } ); p.finally( () => {} 
); p.finally( () => {} ); n(789);
==> produces 2 unhandled-rejection warnings

var y,n; var p = new Promise( (yy,nn) => { y=yy; n=nn } ); p.finally( () => {} 
); p.finally( () => {} ); p.finally( () => {} ); n(789);
==> produces 3 unhandled-rejection warnings

-

Could someone point me to something that would help me to understand the logic 
here? It looks like the first finally() is getting a “free pass” while only the 
2nd and subsequent ones trigger their own unhandled-rejection warnings.

Thank you!

cheers,
-Felipe Gasper
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: performance benchmark of async-design-patterns - recursive-callbacks vs. promises vs. async/await

2018-04-29 Thread Michael J. Ryan
Nice... And not really surprising.  I am slightly surprised async/await is
so close to promises.  Which means that improving promises performance
should probably be a priority.  I still feel the easier to reason with code
is well worth it, given many apps now scale horizontally.

On Sun, Apr 29, 2018, 10:31 kai zhu  wrote:

> fyi, here are some benchmark results of nodejs' client-based http-request
> throughput, employing various async-design-patterns (on a 4gb linode box).
>  overall, recursive-callbacks seem to ~15% faster than both async/await and
> promises (~3000 vs ~2600 client-http-request/s).
>
> ```shell
> $ REQUESTS_PER_TICK=10 node example.js
>
> state 1 - node (v9.11.1)
> state 2 - http-server listening on port 3000
> ...
> state 3 - clientHttpRequestWithRecursiveCallback - flooding http-server
> with request "http://localhost:3000";
> state 5 - clientHttpRequestWithRecursiveCallback - testRun #99
> state 5 - clientHttpRequestWithRecursiveCallback - requestsTotal = 14690
> (in 5009 ms)
> state 5 - clientHttpRequestWithRecursiveCallback - requestsPassed = 7349
> state 5 - clientHttpRequestWithRecursiveCallback - requestsFailed = 7341 ({
> "statusCode - 500": true
> })
> state 5 - clientHttpRequestWithRecursiveCallback - 2933 requests / second
> state 5 - mean requests / second = {
> "clientHttpRequestWithRecursiveCallback": "3059 (156 sigma)",
> "clientHttpRequestWithPromise": "2615 (106 sigma)",
> "clientHttpRequestWithAsyncAwait": "2591 (71 sigma)"
> }
> ```
>
>
> you can reproduce the benchmark-results by running this
> zero-dependency/zero-config, standalone nodejs script below:
>
>
> ```js
> /*
>  * example.js
>  *
>  * this zero-dependency example will benchmark nodejs' client-based
> http-requests throughput,
>  * using recursive-callback/promise/async-await design-patterns.
>  *
>  * the program will make 100 test-runs (randomly picking a design-pattern
> per test-run),
>  * measuring client-based http-requests/seconde over a 5000 ms interval.
>  * it will save the 16 most recent test-runs for each design-pattern,
>  * and print the mean and standard deviation.
>  * any test-run with unusual errors (timeouts, econnreset, etc),
>  * will be discarded and not used in calculations
>  *
>  * the script accepts one env variable $REQUESTS_PER_TICK, which defaults
> to 10
>  * (you can try increasing it if you have a high-performance machine)
>  *
>  *
>  *
>  * example usage:
>  * $ REQUESTS_PER_TICK=10 node example.js
>  *
>  * example output:
>  *
>  * state 1 - node (v9.11.1)
>  * state 2 - http-server listening on port 3000
>  * ...
>  * state 3 - clientHttpRequestWithRecursiveCallback - flooding http-server
> with request "http://localhost:3000";
>  * state 5 - clientHttpRequestWithRecursiveCallback - testRun #99
>  * state 5 - clientHttpRequestWithRecursiveCallback - requestsTotal =
> 14690 (in 5009 ms)
>  * state 5 - clientHttpRequestWithRecursiveCallback - requestsPassed = 7349
>  * state 5 - clientHttpRequestWithRecursiveCallback - requestsFailed =
> 7341 ({
>  * "statusCode - 500": true
>  * })
>  * state 5 - clientHttpRequestWithRecursiveCallback - 2933 requests /
> second
>  * state 5 - mean requests / second = {
>  * "clientHttpRequestWithRecursiveCallback": "3059 (156 sigma)",
>  * "clientHttpRequestWithPromise": "2615 (106 sigma)",
>  * "clientHttpRequestWithAsyncAwait": "2591 (71 sigma)"
>  * }
>  *
>  * state 6 - process.exit(0)
>  */
>
> /*jslint
> bitwise: true,
> browser: true,
> maxerr: 4,
> maxlen: 100,
> node: true,
> nomen: true,
> regexp: true,
> stupid: true
> */
>
> (function () {
> 'use strict';
> var local;
> local = {};
>
> // require modules
> local.http = require('http');
> local.url = require('url');
>
> /* jslint-ignore-begin */
> local.clientHttpRequestWithAsyncAwait = async function (url, onError) {
> /*
>  * this function will make an http-request using async/await
> design-pattern
>  */
> var request, response, timerTimeout;
> try {
> response = await new Promise(function (resolve, reject) {
> // init timeout
> timerTimeout = setTimeout(function () {
> reject(new Error('timeout - 2000 ms'));
> }, 2000);
> request = local.http.request(local.url.parse(url),
> resolve);
>

performance benchmark of async-design-patterns - recursive-callbacks vs. promises vs. async/await

2018-04-29 Thread kai zhu
fyi, here are some benchmark results of nodejs' client-based http-request 
throughput, employing various async-design-patterns (on a 4gb linode box).  
overall, recursive-callbacks seem to ~15% faster than both async/await and 
promises (~3000 vs ~2600 client-http-request/s).

```shell
$ REQUESTS_PER_TICK=10 node example.js

state 1 - node (v9.11.1)
state 2 - http-server listening on port 3000
...
state 3 - clientHttpRequestWithRecursiveCallback - flooding http-server with 
request "http://localhost:3000";
state 5 - clientHttpRequestWithRecursiveCallback - testRun #99
state 5 - clientHttpRequestWithRecursiveCallback - requestsTotal = 14690 (in 
5009 ms)
state 5 - clientHttpRequestWithRecursiveCallback - requestsPassed = 7349
state 5 - clientHttpRequestWithRecursiveCallback - requestsFailed = 7341 ({
"statusCode - 500": true
})
state 5 - clientHttpRequestWithRecursiveCallback - 2933 requests / second
state 5 - mean requests / second = {
"clientHttpRequestWithRecursiveCallback": "3059 (156 sigma)",
"clientHttpRequestWithPromise": "2615 (106 sigma)",
"clientHttpRequestWithAsyncAwait": "2591 (71 sigma)"
}
```


you can reproduce the benchmark-results by running this 
zero-dependency/zero-config, standalone nodejs script below:


```js
/*
 * example.js
 *
 * this zero-dependency example will benchmark nodejs' client-based 
http-requests throughput,
 * using recursive-callback/promise/async-await design-patterns.
 *
 * the program will make 100 test-runs (randomly picking a design-pattern per 
test-run),
 * measuring client-based http-requests/seconde over a 5000 ms interval.
 * it will save the 16 most recent test-runs for each design-pattern,
 * and print the mean and standard deviation.
 * any test-run with unusual errors (timeouts, econnreset, etc),
 * will be discarded and not used in calculations
 *
 * the script accepts one env variable $REQUESTS_PER_TICK, which defaults to 10
 * (you can try increasing it if you have a high-performance machine)
 *
 *
 *
 * example usage:
 * $ REQUESTS_PER_TICK=10 node example.js
 *
 * example output:
 *
 * state 1 - node (v9.11.1)
 * state 2 - http-server listening on port 3000
 * ...
 * state 3 - clientHttpRequestWithRecursiveCallback - flooding http-server with 
request "http://localhost:3000";
 * state 5 - clientHttpRequestWithRecursiveCallback - testRun #99
 * state 5 - clientHttpRequestWithRecursiveCallback - requestsTotal = 14690 (in 
5009 ms)
 * state 5 - clientHttpRequestWithRecursiveCallback - requestsPassed = 7349
 * state 5 - clientHttpRequestWithRecursiveCallback - requestsFailed = 7341 ({
 * "statusCode - 500": true
 * })
 * state 5 - clientHttpRequestWithRecursiveCallback - 2933 requests / second
 * state 5 - mean requests / second = {
 * "clientHttpRequestWithRecursiveCallback": "3059 (156 sigma)",
 * "clientHttpRequestWithPromise": "2615 (106 sigma)",
 * "clientHttpRequestWithAsyncAwait": "2591 (71 sigma)"
 * }
 *
 * state 6 - process.exit(0)
 */

/*jslint
bitwise: true,
browser: true,
maxerr: 4,
maxlen: 100,
node: true,
nomen: true,
regexp: true,
stupid: true
*/

(function () {
'use strict';
var local;
local = {};

// require modules
local.http = require('http');
local.url = require('url');

/* jslint-ignore-begin */
local.clientHttpRequestWithAsyncAwait = async function (url, onError) {
/*
 * this function will make an http-request using async/await design-pattern
 */
var request, response, timerTimeout;
try {
response = await new Promise(function (resolve, reject) {
// init timeout
timerTimeout = setTimeout(function () {
reject(new Error('timeout - 2000 ms'));
}, 2000);
request = local.http.request(local.url.parse(url), resolve);
request.on('error', reject);
request.end();
});
await new Promise(function (resolve, reject) {
// ignore stream-data
response.on('data', local.nop);
if (response.statusCode >= 400) {
reject(new Error('statusCode - ' + response.statusCode));
return;
}
response.on('end', resolve);
response.on('error', reject);
});
} catch (error) {
// cleanup timerTimeout
clearTimeout(timerTimeout);
// cleanup request and response
if (request) {
request.destroy();
}
if (response) {
response.destroy();
}
onError(error);
 

Re: Proposal: Conditional `catch` in Promises

2018-04-26 Thread Isiah Meadows
I agree this isn't ideal (it's a design hack that wasn't very well
thought through on the part of Bluebird IMHO), but not on your
justification (which comes across as borderline off-topic). Most
complex exception handling with promises are effectively handled using
async/await, but I agree the simple stuff shouldn't be made more
complex without justification. If we're going to do type guards like
that, we have to run it in the same tick as the subsequent block, then
for efficiency purposes, what's the point of the guard callback? For a
change this substantial, I'm not convinced it is broadly useful enough
(unlike exception handling with guarded `catch` blocks), especially
with async functions increasingly starting to replace most
promise-heavy code.

-

Isiah Meadows
m...@isiahmeadows.com

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Thu, Apr 26, 2018 at 2:11 AM, kai zhu  wrote:
>
> On 26 Apr 2018, at 12:08 PM, Ayush Gupta  wrote:
>
> It might be worth **explicitly** mentioning that it's not about types
> either, the benefit with using functions as the filter is that we can tackle
> a lot of cases. Consider this:
>
> ```js
> return somePromise
> .catch((reason) => reason instanceof ValidationError, reason =>
> handleValidationError(reason))
> .catch((reason) => reason.code === 'ENOENT', reason =>
> handleENOENT(reason))
> .catch(reason => handleOtherErrors(reason)) // catch all others
> ```
>
>
> can someone give a sane javascript styleguide on when to use the above and
> when to use this code below?  otherwise, we’re simply adding to the
> industry-painpoint of the language having too many cross-cutting
> design-patterns, leading to hard-to-maintain web-projects with inconsistent
> code across its components.
>
> ```js
> return somePromise
> .catch((function (reason) {
> if (reason instanceof ValidationError) {
> return handleValidationError(reason);
> }
> if (reason.code === 'ENOENT') {
> return handleENOENT(reason);
> }
> return handleOtherErrors(reason)) // catch all others
> });
> ```
>
> kai zhu
> kaizhu...@gmail.com
>
>
> On Wed, Apr 25, 2018 at 10:25 PM, Bob Myers  wrote:
>>
>> What do you mean by "approach TypeScript"? Do you mean propose this
>> feature to the TS team? TS is not about new language features (with a few
>> exceptions). It's about typing. They're quite careful about not forking the
>> language.
>>
>> >  Not sure if that supports typed errors
>>
>> No, it doesn't.
>>
>> Bob
>>
>> On Wed, Apr 25, 2018 at 9:49 PM, Michael J. Ryan 
>> wrote:
>>>
>>> Maybe approach typescript on this one... Not sure if that supports typed
>>> errors like C# does, but would probably suit you well.
>>>
>>> On Wed, Apr 25, 2018, 08:31 Isiah Meadows  wrote:
>>>>
>>>> I'd still prefer we wait until pattern matching [1] gets addressed
>>>> first, then tackling this. Error types are represented about 50 different
>>>> ways in JS, with subtyping only being one (used by the standard kind of).
>>>> Node appends an `err.code`, and the DOM adds a similar type, just using a
>>>> common error subclass. And in some cases where errors are planned (but
>>>> exceptions are more convenient), you sometimes see non-errors thrown. So
>>>> there needs to be a means of catching all of them, and `if` checks get
>>>> verbose and noisy in a hurry.
>>>>
>>>> On Wed, Apr 25, 2018, 00:11 Ayush Gupta  wrote:
>>>>>
>>>>> We could potentially provide the same functionality in `try/catch` by
>>>>> extending the signature of `catch` to
>>>>>
>>>>> ```js
>>>>> try {
>>>>>
>>>>> } catch(, ) {
>>>>>
>>>>> }
>>>>> ```
>>>>>
>>>>> If `` evaluates to truthy, invoke the `catch`
>>>>> block, otherwise don't.
>>>>> ___
>>>>> 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
>>>
>>
>
> ___
> 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: Proposal: Conditional `catch` in Promises

2018-04-25 Thread kai zhu

> On 26 Apr 2018, at 12:08 PM, Ayush Gupta  wrote:
> 
> It might be worth **explicitly** mentioning that it's not about types either, 
> the benefit with using functions as the filter is that we can tackle a lot of 
> cases. Consider this:
> 
> ```js
> return somePromise
> .catch((reason) => reason instanceof ValidationError, reason => 
> handleValidationError(reason))
> .catch((reason) => reason.code === 'ENOENT', reason => 
> handleENOENT(reason))
> .catch(reason => handleOtherErrors(reason)) // catch all others
> ```
> 

can someone give a sane javascript styleguide on when to use the above and when 
to use this code below?  otherwise, we’re simply adding to the 
industry-painpoint of the language having too many cross-cutting 
design-patterns, leading to hard-to-maintain web-projects with inconsistent 
code across its components.

```js
return somePromise
.catch((function (reason) {
if (reason instanceof ValidationError) {
return handleValidationError(reason);
}
if (reason.code === 'ENOENT') {
return handleENOENT(reason);
}
return handleOtherErrors(reason)) // catch all others
});
```

kai zhu
kaizhu...@gmail.com

> 
> On Wed, Apr 25, 2018 at 10:25 PM, Bob Myers  > wrote:
> What do you mean by "approach TypeScript"? Do you mean propose this feature 
> to the TS team? TS is not about new language features (with a few 
> exceptions). It's about typing. They're quite careful about not forking the 
> language.
> 
> >  Not sure if that supports typed errors
> 
> No, it doesn't.
> 
> Bob
> 
> On Wed, Apr 25, 2018 at 9:49 PM, Michael J. Ryan  > wrote:
> Maybe approach typescript on this one... Not sure if that supports typed 
> errors like C# does, but would probably suit you well.
> 
> On Wed, Apr 25, 2018, 08:31 Isiah Meadows  > wrote:
> I'd still prefer we wait until pattern matching [1] gets addressed first, 
> then tackling this. Error types are represented about 50 different ways in 
> JS, with subtyping only being one (used by the standard kind of). Node 
> appends an `err.code`, and the DOM adds a similar type, just using a common 
> error subclass. And in some cases where errors are planned (but exceptions 
> are more convenient), you sometimes see non-errors thrown. So there needs to 
> be a means of catching all of them, and `if` checks get verbose and noisy in 
> a hurry.
> 
> On Wed, Apr 25, 2018, 00:11 Ayush Gupta  > wrote:
> We could potentially provide the same functionality in `try/catch` by 
> extending the signature of `catch` to
> 
> ```js
> try {
> 
> } catch(, ) {
> 
> }
> ```
> 
> If `` evaluates to truthy, invoke the `catch` block, 
> otherwise don't.
> ___
> 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 
> 
> 
> 
> 
> ___
> 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: Re: Proposal: Conditional `catch` in Promises

2018-04-25 Thread Ayush Gupta
It might be worth **explicitly** mentioning that it's not about types
either, the benefit with using functions as the filter is that we can
tackle a lot of cases. Consider this:

```js
return somePromise
.catch((reason) => reason instanceof ValidationError, reason =>
handleValidationError(reason))
.catch((reason) => reason.code === 'ENOENT', reason =>
handleENOENT(reason))
.catch(reason => handleOtherErrors(reason)) // catch all others
```


On Wed, Apr 25, 2018 at 10:25 PM, Bob Myers  wrote:

> What do you mean by "approach TypeScript"? Do you mean propose this
> feature to the TS team? TS is not about new language features (with a few
> exceptions). It's about typing. They're quite careful about not forking the
> language.
>
> >  Not sure if that supports typed errors
>
> No, it doesn't.
>
> Bob
>
> On Wed, Apr 25, 2018 at 9:49 PM, Michael J. Ryan 
> wrote:
>
>> Maybe approach typescript on this one... Not sure if that supports typed
>> errors like C# does, but would probably suit you well.
>>
>> On Wed, Apr 25, 2018, 08:31 Isiah Meadows  wrote:
>>
>>> I'd still prefer we wait until pattern matching [1] gets addressed
>>> first, then tackling this. Error types are represented about 50 different
>>> ways in JS, with subtyping only being one (used by the standard kind of).
>>> Node appends an `err.code`, and the DOM adds a similar type, just using a
>>> common error subclass. And in some cases where errors are planned (but
>>> exceptions are more convenient), you sometimes see non-errors thrown. So
>>> there needs to be a means of catching all of them, and `if` checks get
>>> verbose and noisy in a hurry.
>>>
>>> On Wed, Apr 25, 2018, 00:11 Ayush Gupta  wrote:
>>>
 We could potentially provide the same functionality in `try/catch` by
 extending the signature of `catch` to

 ```js
 try {

 } catch(, ) {

 }
 ```

 If `` evaluates to truthy, invoke the `catch`
 block, otherwise don't.
 ___
 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
>>
>>
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Re: Proposal: Conditional `catch` in Promises

2018-04-25 Thread Bob Myers
What do you mean by "approach TypeScript"? Do you mean propose this feature
to the TS team? TS is not about new language features (with a few
exceptions). It's about typing. They're quite careful about not forking the
language.

>  Not sure if that supports typed errors

No, it doesn't.

Bob

On Wed, Apr 25, 2018 at 9:49 PM, Michael J. Ryan  wrote:

> Maybe approach typescript on this one... Not sure if that supports typed
> errors like C# does, but would probably suit you well.
>
> On Wed, Apr 25, 2018, 08:31 Isiah Meadows  wrote:
>
>> I'd still prefer we wait until pattern matching [1] gets addressed first,
>> then tackling this. Error types are represented about 50 different ways in
>> JS, with subtyping only being one (used by the standard kind of). Node
>> appends an `err.code`, and the DOM adds a similar type, just using a common
>> error subclass. And in some cases where errors are planned (but exceptions
>> are more convenient), you sometimes see non-errors thrown. So there needs
>> to be a means of catching all of them, and `if` checks get verbose and
>> noisy in a hurry.
>>
>> On Wed, Apr 25, 2018, 00:11 Ayush Gupta  wrote:
>>
>>> We could potentially provide the same functionality in `try/catch` by
>>> extending the signature of `catch` to
>>>
>>> ```js
>>> try {
>>>
>>> } catch(, ) {
>>>
>>> }
>>> ```
>>>
>>> If `` evaluates to truthy, invoke the `catch`
>>> block, otherwise don't.
>>> ___
>>> 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
>
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Re: Proposal: Conditional `catch` in Promises

2018-04-25 Thread Michael J. Ryan
Maybe approach typescript on this one... Not sure if that supports typed
errors like C# does, but would probably suit you well.

On Wed, Apr 25, 2018, 08:31 Isiah Meadows  wrote:

> I'd still prefer we wait until pattern matching [1] gets addressed first,
> then tackling this. Error types are represented about 50 different ways in
> JS, with subtyping only being one (used by the standard kind of). Node
> appends an `err.code`, and the DOM adds a similar type, just using a common
> error subclass. And in some cases where errors are planned (but exceptions
> are more convenient), you sometimes see non-errors thrown. So there needs
> to be a means of catching all of them, and `if` checks get verbose and
> noisy in a hurry.
>
> On Wed, Apr 25, 2018, 00:11 Ayush Gupta  wrote:
>
>> We could potentially provide the same functionality in `try/catch` by
>> extending the signature of `catch` to
>>
>> ```js
>> try {
>>
>> } catch(, ) {
>>
>> }
>> ```
>>
>> If `` evaluates to truthy, invoke the `catch` block,
>> otherwise don't.
>> ___
>> 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: Re: Proposal: Conditional `catch` in Promises

2018-04-25 Thread Isiah Meadows
I'd still prefer we wait until pattern matching [1] gets addressed first,
then tackling this. Error types are represented about 50 different ways in
JS, with subtyping only being one (used by the standard kind of). Node
appends an `err.code`, and the DOM adds a similar type, just using a common
error subclass. And in some cases where errors are planned (but exceptions
are more convenient), you sometimes see non-errors thrown. So there needs
to be a means of catching all of them, and `if` checks get verbose and
noisy in a hurry.

On Wed, Apr 25, 2018, 00:11 Ayush Gupta  wrote:

> We could potentially provide the same functionality in `try/catch` by
> extending the signature of `catch` to
>
> ```js
> try {
>
> } catch(, ) {
>
> }
> ```
>
> If `` evaluates to truthy, invoke the `catch` block,
> otherwise don't.
> ___
> 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: Re: Proposal: Conditional `catch` in Promises

2018-04-24 Thread Ayush Gupta
We could potentially provide the same functionality in `try/catch` by
extending the signature of `catch` to

```js
try {

} catch(, ) {

}
```

If `` evaluates to truthy, invoke the `catch` block,
otherwise don't.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Proposal: Conditional `catch` in Promises

2018-04-24 Thread T.J. Crowder
For my part, if we're going to get into optional catching, I'd rather see a
common approach between promise `catch` and `try`/`catch`. There have been
various discussions about optional/filtered `catch` on the list ([here][1]
and [here][2], probably others).

Your approach is easily implemented in userland:

```js
const cif = (predicate, handler) => e => {
if (predicate(e)) {
return handler(e);
}
throw e;
};
```

then

```js
somePromise
.catch(cif(reason => reason instanceof ValidationError, reason =>
handleValidationError(reason))) // handle ValidationErrors
.catch(cif(reason => reason instanceof InternalError, reason =>
handleInternalError(reason))) // handle InternalErrors
.catch(cif(reason => handleOtherErrors(reason))); // catch all others
```

https://jsfiddle.net/maov8y0h/

To be clear, I'm not saying that just because something can be implemented
in userland, it shouldn't be considered. (Lots of things can be implemented
in userland.) But again, I'd want to see a cohesive approach, and I think
this probably doesn't take us in that direction.

-- T.J. Crowder

[1]: https://esdiscuss.org/topic/standardizing-conditional-try-catch
[2]: https://esdiscuss.org/topic/filtered-promise-catch

On Tue, Apr 24, 2018 at 10:35 AM, Ayush Gupta
 wrote:
> I propose that in `Promises`, we accept another function which returns a
> `boolean` as an argument to `catch`. It will enable us to write code like
> this:
>
> ```js
> return somePromise
> .catch((reason) => reason instanceof ValidationError, reason =>
> handleValidationError(reason)) // handle ValidationErrors
> .catch((reason) => reason instanceof InternalError, reason =>
> handleInternalError(reason)) // handle InternalErrors
> .catch(reason => handleOtherErrors(reason)) // catch all others
> ```
>
> If the passed function evaluates to `true`, call the actual rejection
> handler. If none of the catch are eligible to handle the rejection, it
> causes an unhandled rejection.
>
> ___
> 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


Proposal: Conditional `catch` in Promises

2018-04-24 Thread Ayush Gupta
I propose that in `Promises`, we accept another function which returns a
`boolean` as an argument to `catch`. It will enable us to write code like
this:

```js
return somePromise
.catch((reason) => reason instanceof ValidationError, reason =>
handleValidationError(reason)) // handle ValidationErrors
.catch((reason) => reason instanceof InternalError, reason =>
handleInternalError(reason)) // handle InternalErrors
.catch(reason => handleOtherErrors(reason)) // catch all others
```

If the passed function evaluates to `true`, call the actual rejection
handler. If none of the catch are eligible to handle the rejection, it
causes an unhandled rejection.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Cancel Promise pattern (no cancellable promises)

2017-11-29 Thread Isiah Meadows
On Wed, Nov 29, 2017, 19:19 /#!/JoePea  wrote:

> Hello all, I'm posting here because I'm thinking about how not to leak
> memory, and wondering if I am.
>
> Suppose I have an object that is cleaned up (GC'd), and that object's
> constructor (for example) ran an anonymous function that listened to a
> Promise. For exampel:
>
> ```js
> class Foo {
>   constructor() {
> // ...
> this.somePromise.then(() => {console.log('this will never fire if this
> object is GC'd')})
>   }
> }
> ```
>
> Suppose that if this object gets collected, then it means that there is
> nothing in my application that will ever be able to resolve this object's
> `somePromise`.
>

> Does the engine also garbage collect `somePromise` and the attached
> handler?
>

Yes, provided nothing else is referencing it.


> Now, what if `somePromise` is referenced outside of this object by some
> other code waiting on yet another promise who's handler will resolve this
> object's `somePromise`? Does this prevent the object from being GC'd? Or is
> the object GC'd, but `somePromise` is not and the above console.log should
> still fire at some point (or memory will be leaked)?
>

The object itself is GC'd independently of its members absent a circular
reference.

A thing to keep in mind is that a promise could still be referenced by its
resolving functions, even if the promise itself is no longer referenced by
ECMAScript code. This keeps the promise state alive, so it can still fire
(otherwise, you'd have observable GC). So, in this example, things will
still fire regardless:

```js
function foo() {
let p = new Promise(resolve => {
setTimeout(resolve, 1000)
})

p.then(() => {
console.log("This still fires")
})

// `p` is no longer referenced by the
// calling function, but it's still referenced
// by the enqueued `setTimeout` task, so
// it can't be collected
}

foo()
```


>
> */#!/*JoePea
>
> On Thu, Jan 12, 2017 at 1:12 PM, Isiah Meadows 
> wrote:
>
>> And that's why we're waiting on the next meeting to happen with notes
>> posted, so we can figure out what to do next. It's likely to get discussed,
>> especially considering the current situation and pressing need for it.
>>
>> On Thu, Jan 12, 2017, 13:27 Jordan Harband  wrote:
>>
>>> The Cancellable Promises proposal itself is currently withdrawn, but
>>> don't forget that all of the previous discussion on cancellation in
>>> promises led to that proposal.
>>>
>>> It would be shortsighted to pretend they don't exist, or that the spec
>>> proposal won't matter forever to any other cancellation proposal, and doing
>>> so won't help any alternative proposal.
>>>
>>> On Thu, Jan 12, 2017 at 7:44 AM, Jan-Ivar Bruaroey 
>>> wrote:
>>>
>>> Cancellable promises is dead. Please don't hijack this thread discussing
>>> them.
>>>
>>> Thanks,
>>>
>>> .: Jan-Ivar :.
>>>
>>>
>>> ___
>>> 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
>>
>>
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Cancel Promise pattern (no cancellable promises)

2017-11-29 Thread /#!/JoePea
Hello all, I'm posting here because I'm thinking about how not to leak
memory, and wondering if I am.

Suppose I have an object that is cleaned up (GC'd), and that object's
constructor (for example) ran an anonymous function that listened to a
Promise. For exampel:

```js
class Foo {
  constructor() {
// ...
this.somePromise.then(() => {console.log('this will never fire if this
object is GC'd')})
  }
}
```

Suppose that if this object gets collected, then it means that there is
nothing in my application that will ever be able to resolve this object's
`somePromise`.

Does the engine also garbage collect `somePromise` and the attached handler?

Now, what if `somePromise` is referenced outside of this object by some
other code waiting on yet another promise who's handler will resolve this
object's `somePromise`? Does this prevent the object from being GC'd? Or is
the object GC'd, but `somePromise` is not and the above console.log should
still fire at some point (or memory will be leaked)?


*/#!/*JoePea

On Thu, Jan 12, 2017 at 1:12 PM, Isiah Meadows 
wrote:

> And that's why we're waiting on the next meeting to happen with notes
> posted, so we can figure out what to do next. It's likely to get discussed,
> especially considering the current situation and pressing need for it.
>
> On Thu, Jan 12, 2017, 13:27 Jordan Harband  wrote:
>
>> The Cancellable Promises proposal itself is currently withdrawn, but
>> don't forget that all of the previous discussion on cancellation in
>> promises led to that proposal.
>>
>> It would be shortsighted to pretend they don't exist, or that the spec
>> proposal won't matter forever to any other cancellation proposal, and doing
>> so won't help any alternative proposal.
>>
>> On Thu, Jan 12, 2017 at 7:44 AM, Jan-Ivar Bruaroey 
>> wrote:
>>
>> Cancellable promises is dead. Please don't hijack this thread discussing
>> them.
>>
>> Thanks,
>>
>> .: Jan-Ivar :.
>>
>>
>> ___
>> 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
>
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Promises, async functions, and requestAnimationFrame, together.

2017-03-18 Thread /#!/JoePea
Ah, I think the reason that this animation loop using promises works is
because promise handlers resolve in the next microtask after the current
macrotask. I believe that the animation frame fires in what is essentially
a macrotask, then immediately after this macrotask the resolution of the
`animationFrame()` promise happens in the following microtask. At some
point later, the browser renders stuff, which I think might the next
macrotask after the animation frame macrotask.

*/#!/*JoePea
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Enable async/await to work on functions that don't just return promises.

2017-02-27 Thread Isiah Meadows
I'm guessing you missed the second sentence in my reply about the fact I'm
strongly against the original proposal...

On Mon, Feb 27, 2017, 17:24 Michał Wadas  wrote:

> Actually, this proposal would be a revolution and I can think of too many
> edge cases to make it viable.
>
> Consider:
>
> async function foo() {
>
> async function bar() {
>
> [1,2,3].forEach(async function() {
> async return 3; });
>
> }
> return (await bar()) + 39;
>
> }
>
> What does happen here? For me it's absolutely counterintuitive.
> What about functions coming from other scopes, like?
>
> async function foo() {
>
> function bar() {
>
> [1,2,3].forEach(async function() {
> async return 3; });
>
> }
> return (await bar()) + 39;
>
> }
>
> Or multiple returns?
>
>
> async function foo() {
>
> setTimeout(()=>{ async return 42; }, 0);
> return null;
>
> }
>
>
> Promisification should be done by userland libraries, not by introducing
> new syntax.
>
>
>
>
> On 27/02/17 22:17, Isiah Meadows wrote:
>
> I was speaking objectively about the proposal itself, and the scope of it.
> I'm personally strongly against it for reasons I stated earlier in the
> thread (the status quo is better IMHO). I was just trying to direct people
> back to the actual scope of the proposal instead of basically reinventing
> async functions using async functions, and also simultaneously attempting
> to assist the OP in better understanding what he's really trying to propose
> (which he didn't appear to grasp well).
>
> On Mon, Feb 27, 2017, 14:01 Tab Atkins Jr.  wrote:
>
> On Mon, Feb 27, 2017 at 12:41 AM, Isiah Meadows 
> wrote:
> > May I add one more thing: the main topic this was about is adapting
> > non-standard async APIs (like Node's error-first callback idiom) to the
> land
> > of promises. Async functions and iterators are incredibly useful when
> you're
> > dealing with just promises, especially consuming them, but this is about
> > creating promise adapters, not consuming promises.
>
> You don't need to change the behavior of core syntax to make
> Node-style error-first callbacks work.  That's easily done by
> libraries, which have existed in Node-land for quite a while, and can
> automatically convert functions that take Node-style callbacks into
> functions that return promises.
>
> ~TJ
>
>
>
> ___
> es-discuss mailing 
> listes-discuss@mozilla.orghttps://mail.mozilla.org/listinfo/es-discuss
>
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Enable async/await to work on functions that don't just return promises.

2017-02-27 Thread Michał Wadas
Actually, this proposal would be a revolution and I can think of too
many edge cases to make it viable.

Consider:

async function foo() {

async function bar() {

[1,2,3].forEach(async function() { async return
3;  });

} return (await bar()) + 39;

}

What does happen here? For me it's absolutely counterintuitive.
What about functions coming from other scopes, like?

async function foo() {

function bar() {

[1,2,3].forEach(async function() { async return
3;  });

} return (await bar()) + 39;

}

Or multiple returns?


async function foo() {

setTimeout(()=>{ async return 42; }, 0); return null;

}


Promisification should be done by userland libraries, not by introducing
new syntax.



On 27/02/17 22:17, Isiah Meadows wrote:
> I was speaking objectively about the proposal itself, and the scope of
> it. I'm personally strongly against it for reasons I stated earlier in
> the thread (the status quo is better IMHO). I was just trying to
> direct people back to the actual scope of the proposal instead of
> basically reinventing async functions using async functions, and also
> simultaneously attempting to assist the OP in better understanding
> what he's really trying to propose (which he didn't appear to grasp
> well). 
>
> On Mon, Feb 27, 2017, 14:01 Tab Atkins Jr.  <mailto:jackalm...@gmail.com>> wrote:
>
> On Mon, Feb 27, 2017 at 12:41 AM, Isiah Meadows
> mailto:isiahmead...@gmail.com>> wrote:
> > May I add one more thing: the main topic this was about is adapting
> > non-standard async APIs (like Node's error-first callback idiom)
> to the land
> > of promises. Async functions and iterators are incredibly useful
> when you're
> > dealing with just promises, especially consuming them, but this
> is about
> > creating promise adapters, not consuming promises.
>
> You don't need to change the behavior of core syntax to make
> Node-style error-first callbacks work.  That's easily done by
> libraries, which have existed in Node-land for quite a while, and can
> automatically convert functions that take Node-style callbacks into
> functions that return promises.
>
> ~TJ
>
>
>
> ___
> 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: Enable async/await to work on functions that don't just return promises.

2017-02-27 Thread Isiah Meadows
I was speaking objectively about the proposal itself, and the scope of it.
I'm personally strongly against it for reasons I stated earlier in the
thread (the status quo is better IMHO). I was just trying to direct people
back to the actual scope of the proposal instead of basically reinventing
async functions using async functions, and also simultaneously attempting
to assist the OP in better understanding what he's really trying to propose
(which he didn't appear to grasp well).

On Mon, Feb 27, 2017, 14:01 Tab Atkins Jr.  wrote:

> On Mon, Feb 27, 2017 at 12:41 AM, Isiah Meadows 
> wrote:
> > May I add one more thing: the main topic this was about is adapting
> > non-standard async APIs (like Node's error-first callback idiom) to the
> land
> > of promises. Async functions and iterators are incredibly useful when
> you're
> > dealing with just promises, especially consuming them, but this is about
> > creating promise adapters, not consuming promises.
>
> You don't need to change the behavior of core syntax to make
> Node-style error-first callbacks work.  That's easily done by
> libraries, which have existed in Node-land for quite a while, and can
> automatically convert functions that take Node-style callbacks into
> functions that return promises.
>
> ~TJ
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Enable async/await to work on functions that don't just return promises.

2017-02-27 Thread Tab Atkins Jr.
On Mon, Feb 27, 2017 at 12:41 AM, Isiah Meadows  wrote:
> May I add one more thing: the main topic this was about is adapting
> non-standard async APIs (like Node's error-first callback idiom) to the land
> of promises. Async functions and iterators are incredibly useful when you're
> dealing with just promises, especially consuming them, but this is about
> creating promise adapters, not consuming promises.

You don't need to change the behavior of core syntax to make
Node-style error-first callbacks work.  That's easily done by
libraries, which have existed in Node-land for quite a while, and can
automatically convert functions that take Node-style callbacks into
functions that return promises.

~TJ
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Enable async/await to work on functions that don't just return promises.

2017-02-27 Thread Andy Earnshaw
I had a similar thought a while ago for adapting non-promise functions, by
way of `async.resolve()` and `async.reject()`:

```javascript
async function asyncFunction() {
someAsync('data', (err, data) => {
if (err) async.reject(err);
async.resolve(data);
})
}
```

This differs from your proposal in that it's more explicit.  Neither really
give much benefit beyond saving a few bytes of code, probably not worth the
extra complexity.  It might be ok as an API, e.g. Promise.adapt(someAsync),
but the downside there is that it can't be very generic (an argument could
be made for the very common Node callback pattern where the last argument
to the function is the callback and the params are always err, result).

There are also existing NPM libraries to "promisify" module exports.

On Mon, 27 Feb 2017 at 08:42 Isiah Meadows  wrote:

> May I add one more thing: the main topic this was about is adapting
> non-standard async APIs (like Node's error-first callback idiom) to the
> land of promises. Async functions and iterators are incredibly useful when
> you're dealing with just promises, especially consuming them, but this is
> about creating promise adapters, not consuming promises.
>
> On Sun, Feb 26, 2017, 18:52 Mark  wrote:
>
> Codefined, just out of curiousity, do you have anything to do with this
> proposal that got announced today
> <https://github.com/tc39/proposals/pull/41>? Or is it just a coincidence?
> :)
> ​
>
> On Sun, Feb 26, 2017 at 3:07 PM Dean Tribble  wrote:
>
> Should `callee()` be asynchronous here?  To my mind, no, it shouldn't.
> Every single line here is synchronous, so the function itself should surely
> be synchronous.  Shouldn't functions that may not have `await` in them, but
> instead that are actually asynchronous and hence use the `async return`
> keyword be the ones we define with `async`?
>
>
> In the Javascript (and Midori) model, concurrent execution of multiple
> activities is achieved by breaking those activities up into coarse-grained,
> application-defined "turns" (or "jobs") and interleaving those.  An async
> boundary is where the current turn could end, and the turns for other
> concurrent activities might run, changing the state before the current
> activity proceeds.
>
> Therefore, callee must be async, because that declares that there could
> be a turn boundary within it, and thus, the rest of the state of the
> program could change as a result of the call.  The caller of callee *must
> *ensure that it's invariants are correct before allowing other code to
> interleave with it.
>
> ___
> 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
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Enable async/await to work on functions that don't just return promises.

2017-02-27 Thread Isiah Meadows
May I add one more thing: the main topic this was about is adapting
non-standard async APIs (like Node's error-first callback idiom) to the
land of promises. Async functions and iterators are incredibly useful when
you're dealing with just promises, especially consuming them, but this is
about creating promise adapters, not consuming promises.

On Sun, Feb 26, 2017, 18:52 Mark  wrote:

> Codefined, just out of curiousity, do you have anything to do with this
> proposal that got announced today
> <https://github.com/tc39/proposals/pull/41>? Or is it just a coincidence?
> :)
> ​
>
> On Sun, Feb 26, 2017 at 3:07 PM Dean Tribble  wrote:
>
> Should `callee()` be asynchronous here?  To my mind, no, it shouldn't.
> Every single line here is synchronous, so the function itself should surely
> be synchronous.  Shouldn't functions that may not have `await` in them, but
> instead that are actually asynchronous and hence use the `async return`
> keyword be the ones we define with `async`?
>
>
> In the Javascript (and Midori) model, concurrent execution of multiple
> activities is achieved by breaking those activities up into coarse-grained,
> application-defined "turns" (or "jobs") and interleaving those.  An async
> boundary is where the current turn could end, and the turns for other
> concurrent activities might run, changing the state before the current
> activity proceeds.
>
> Therefore, callee must be async, because that declares that there could
> be a turn boundary within it, and thus, the rest of the state of the
> program could change as a result of the call.  The caller of callee *must
> *ensure that it's invariants are correct before allowing other code to
> interleave with it.
>
> ___
> 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: Enable async/await to work on functions that don't just return promises.

2017-02-26 Thread Mark
Codefined, just out of curiousity, do you have anything to do with this
proposal that got announced today
? Or is it just a coincidence? :)
​

On Sun, Feb 26, 2017 at 3:07 PM Dean Tribble  wrote:

> Should `callee()` be asynchronous here?  To my mind, no, it shouldn't.
> Every single line here is synchronous, so the function itself should surely
> be synchronous.  Shouldn't functions that may not have `await` in them, but
> instead that are actually asynchronous and hence use the `async return`
> keyword be the ones we define with `async`?
>
>
> In the Javascript (and Midori) model, concurrent execution of multiple
> activities is achieved by breaking those activities up into coarse-grained,
> application-defined "turns" (or "jobs") and interleaving those.  An async
> boundary is where the current turn could end, and the turns for other
> concurrent activities might run, changing the state before the current
> activity proceeds.
>
> Therefore, callee must be async, because that declares that there could
> be a turn boundary within it, and thus, the rest of the state of the
> program could change as a result of the call.  The caller of callee *must
> *ensure that it's invariants are correct before allowing other code to
> interleave with it.
>
> ___
> 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: Enable async/await to work on functions that don't just return promises.

2017-02-26 Thread Dean Tribble
>
> Should `callee()` be asynchronous here?  To my mind, no, it shouldn't.
> Every single line here is synchronous, so the function itself should surely
> be synchronous.  Shouldn't functions that may not have `await` in them, but
> instead that are actually asynchronous and hence use the `async return`
> keyword be the ones we define with `async`?


In the Javascript (and Midori) model, concurrent execution of multiple
activities is achieved by breaking those activities up into coarse-grained,
application-defined "turns" (or "jobs") and interleaving those.  An async
boundary is where the current turn could end, and the turns for other
concurrent activities might run, changing the state before the current
activity proceeds.

Therefore, callee must be async, because that declares that there could be
a turn boundary within it, and thus, the rest of the state of the program
could change as a result of the call.  The caller of callee *must *ensure
that it's invariants are correct before allowing other code to interleave
with it.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Enable async/await to work on functions that don't just return promises.

2017-02-26 Thread Codefined
A very interesting read indeed Alexander!  Gave me a new example to give when 
people ask what the worst code I'd ever seen was:
Promise DoSomething(Promise cmd) { return cmd.WhenResolved( s => 
{ if (s == "...") { return DoSomethingElse(...).WhenResolved( v => { return 
...; }, e => { Log(e); throw e; } ); } else { return ...; } }, e => { Log(e); 
throw e; } ); }
My question is however, that this article defines that an `await` keyword must 
be within an `async` function, which seems an interesting choice to me.  For 
example, the following code snippet:
function callee() { let x = await someAsync(); }
Should `callee()` be asynchronous here?  To my mind, no, it shouldn't.  Every 
single line here is synchronous, so the function itself should surely be 
synchronous.  Shouldn't functions that may not have `await` in them, but 
instead that are actually asynchronous and hence use the `async return` keyword 
be the ones we define with `async`?

Although, saying that, I think I may steal their use of `async Bar()` when 
calling functions and add it to the proposal.  It makes sense to me that `let x 
= someAsync()` should error out to let developers know they're doing something 
wrong.  `let x = async someAsync()` clearly does show that they know the 
function is async and will return a promise..___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Enable async/await to work on functions that don't just return promises.

2017-02-26 Thread Alexander Jones
Required reading for anyone who wants to be so... opinionated ;)

http://joeduffyblog.com/2015/11/19/asynchronous-everything/

On Sun, 26 Feb 2017 at 16:35, Florian Bösch  wrote:

> On Sun, Feb 26, 2017 at 5:30 PM, Codefined 
> wrote:
>
> I'll be interested to see what you guys consider the
> advantages/disadvantages of this method, which I hope to be "the middle
> between two ends" on whether to go fully into promises or fully into
> co-routines.  Neither of which are in my opinion the optimal stance.
>
>
> Hereabouts nobody's going to either full co-routines or even semi-implicit
> co-routines. But JS doesn't matter, just compile to asm.js/WebAssembly or
> write a bytecode engine atop JS etc. from a language that actually solves
> concurrent programming well and isn't a hodgepodge of missed opportunities.
> ___
> 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: Enable async/await to work on functions that don't just return promises.

2017-02-26 Thread Codefined
You seem to be feel incredibly jaded about nearly everything posted here.  
Perhaps if you suggested your own proposal that showed the clear advantages of 
co-routines as you see it, then you might solve some of the issues instead of 
just whining about it.

I assume that every single Javascript developer out there just wants the best 
for the language as a whole, so maybe you should look at the counter-arguments 
to co-routines to see where they're coming from and attempt to fix them?
On 26/02/2017 16:35:16, Florian Bösch  wrote:
On Sun, Feb 26, 2017 at 5:30 PM, Codefined mailto:codefi...@debenclipper.com]> wrote:

I'll be interested to see what you guys consider the advantages/disadvantages 
of this method, which I hope to be "the middle between two ends" on whether to 
go fully into promises or fully into co-routines.  Neither of which are in my 
opinion the optimal stance.
 
Hereabouts nobody's going to either full co-routines or even semi-implicit 
co-routines. But JS doesn't matter, just compile to asm.js/WebAssembly or write 
a bytecode engine atop JS etc. from a language that actually solves concurrent 
programming well and isn't a hodgepodge of missed opportunities.___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Enable async/await to work on functions that don't just return promises.

2017-02-26 Thread Florian Bösch
On Sun, Feb 26, 2017 at 5:30 PM, Codefined 
wrote:

> I'll be interested to see what you guys consider the
> advantages/disadvantages of this method, which I hope to be "the middle
> between two ends" on whether to go fully into promises or fully into
> co-routines.  Neither of which are in my opinion the optimal stance.
>

Hereabouts nobody's going to either full co-routines or even semi-implicit
co-routines. But JS doesn't matter, just compile to asm.js/WebAssembly or
write a bytecode engine atop JS etc. from a language that actually solves
concurrent programming well and isn't a hodgepodge of missed opportunities.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Enable async/await to work on functions that don't just return promises.

2017-02-26 Thread Codefined
Thank-you guys for the excellent problems with the previous idea, to attempt to 
fix as many of them as I can, here is an alteration to the proposal:

You have two types of functions, asynchronous and synchronous functions.  To 
distinguish between them, an asynchronous function has the keyword of `async` 
prepended before it.  Also, unlike the `return` statement in a synchronous 
function, the asynchronous code has `async return`.  Examples:
function someSync() { return "Sync"; } async function someAsync() { 
setTimeout(() => { async return "Async"; }, 1000); }
The synchronous code is called as one would expect, however the asynchronous 
code can be called in two ways:
function calleeOne() { let x = await someAsync(); } function calleeTwo() { let 
x = someAsync(); }
You'll notice the main difference between this latest iteration and the first 
proposal is that you do not need to put `async` around your callee function.  
In the first case, the code waits until `x` has a value, here the value will be 
"Async" after one second.  In the second case, the code continues on instantly, 
with `x` being an automatically wrapped promise.  This has many advantages, 
including the most obvious example given by Florian:
// Assumes a function `someAsync()` which is an asychronous function. function 
c() { return d() } function d() { return await someAsync() }
You'll notice we've simply made `someAsync()` as a function, synchronous.  No 
code changes are needed above the `c()` function, unlike in the previous 
proposal iteration.

I'll be interested to see what you guys consider the advantages/disadvantages 
of this method, which I hope to be "the middle between two ends" on whether to 
go fully into promises or fully into co-routines.  Neither of which are in my 
opinion the optimal stance.
On 26/02/2017 14:31:30, Florian Bösch  wrote:
await/async are de-facto co-routines. await/async will infect all code by 
necessity of software engineering. At which point they're actual co-routines, 
implemented badly, without a proper API.

On Sun, Feb 26, 2017 at 3:26 PM, Jerald Cohen mailto:cohenjera...@gmail.com]> wrote:

Florian,

You sure you're not just adding more complexities to a language with features 
that were _meant_ to remove such complexity?


Codefined's solution to me seems to be the one with the least amount of added 
techniques in order to learn.  Although I understand how co-rountines are 
awesome, they can quickly get very confusing when you switch contexts.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Enable async/await to work on functions that don't just return promises.

2017-02-26 Thread Florian Bösch
await/async are de-facto co-routines. await/async will infect all code by
necessity of software engineering. At which point they're actual
co-routines, implemented badly, without a proper API.

On Sun, Feb 26, 2017 at 3:26 PM, Jerald Cohen 
wrote:

> Florian,
>
> You sure you're not just adding more complexities to a language with
> features that were _meant_ to remove such complexity?
>
> Codefined's solution to me seems to be the one with the least amount of
> added techniques in order to learn.  Although I understand how co-rountines
> are awesome, they can quickly get very confusing when you switch contexts.
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Enable async/await to work on functions that don't just return promises.

2017-02-26 Thread Jerald Cohen
Florian,

You sure you're not just adding more complexities to a language with
features that were _meant_ to remove such complexity?

Codefined's solution to me seems to be the one with the least amount of
added techniques in order to learn.  Although I understand how co-rountines
are awesome, they can quickly get very confusing when you switch contexts.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Enable async/await to work on functions that don't just return promises.

2017-02-26 Thread Florian Bösch
On Sun, Feb 26, 2017 at 2:51 PM, Codefined 
wrote:

> What I feel we need is some way of making an asynchronous function
> "appear" to be synchronous.
>
That's what co-routines are. Best practices for co-routines is usually to
have some sort of API to spawn them (like new Routine(somefunction)), to be
able to switch to them (like someroutine.switch(funargs)) and to throw
exceptions into them (like someroutine.throw(error)) as well as a way to
obtain the currently used routine (like Routine.current).
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Enable async/await to work on functions that don't just return promises.

2017-02-26 Thread Codefined
Ah, that would indeed make sense.  What I feel we need is some way of making an 
asynchronous function "appear" to be synchronous.  Actually that's sort of what 
I expected async/await to do, but that only seems to affect where it's called, 
as opposed to the function itself.___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Enable async/await to work on functions that don't just return promises.

2017-02-26 Thread Florian Bösch
On Sun, Feb 26, 2017 at 2:17 PM, Codefined 
wrote:

> Because `d()` is no longer an asynchronous function, you can call it like
> normal, surely?
>

Only async functions can await. Only await pauses execution to wait on
async.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Enable async/await to work on functions that don't just return promises.

2017-02-26 Thread Codefined
Hey Florian,

Why do we even need to do that?
async function someAsync() { something(() => { return "hello"; }); } let d = 
function() { return await someAsync(); } let c = function() { return d(); }
Because `d()` is no longer an asynchronous function, you can call it like 
normal, surely?


On 26/02/2017 12:44:01, Florian Bösch  wrote:
It would be nice if there even was an argument, but there isn't. There isn't 
because async/await naturally devolves into implicit coroutines, so any 
argument would be moot.

To illustrate, suppose you have these 4 functions:

let a = function(){
  return b();
}

let b = function(){
  return c();
}

let c = function(){
   return d();
}

let d = function(){
  return whatever();
}

Call chains like this are typical. It's the staple of software engineering (for 
reasons of proper separation of concerns, reuse of utility code, etc.). If you 
believe that there is an argument about this being exemplary, it would be 
impossible to have an argument with you about software engineering at all. Of 
course real-world examples are more complex and don't just return whatever the 
underlying function produced, but as a control flow example it suffices. These 
chains are often much deeper than 4 levels, it's not uncommon to encounter call 
chains 10, 15, 20 or 30 layers deep.

Now let's suppose you figure that function d wants to do something asynchronous.

So you go and do:

let d = function(){
  return xhr();
}

But of course that doesn't work, because d is not async. So you go and do:

let d = async function(){
  return await xhr();
}

Of course that doesn't work because c is not async, and so forth, so eventually 
your code looks like that.

let a = async function(){
  return await b();
}

let b = async function(){
  return await c();
}

let c = async function(){
   return await d();
}

let d = async function(){
  return await xhr();
}

In essence, you've applied to following two regular expression: 
s/function/await function/g and s/.+?\(\)/await ()/ . Of course that'd be 
horrid to do, so in reality you'd please use a proper JS parser. How did your 
code look before you applied these regular expressions? Well, it looks exactly 
like at the start.

let a = function(){
  return b();
}

let b = function(){
  return c();
}

let c = function(){
   return d();
}

let d = function(){
  return xhr();
}

But it isn't like at the start, because now it can trigger race conditions and 
is asynchronous. It is in fact now idempotent with true co-routines, except 
some unnecessary code transmoglification.

This conclusively proves that await/async is an inconvenient clutch that 
naturally devolves into true co-routines. Now you might try to argue, that 
real-world code isn't just going to prefix every function call with await and 
every function body with async and stay that way.

However, this would be in invalid argument for actual real-world code, because. 
People don't just constantly switch back and forth and re-engineer their code 
just because they want something async to happen underneath. You don't go and 
bicycle repair every call and function definition if you should decide to 
toggle synchronous or asynchronous. Therefore, since prefixing everything works 
no matter if it is asynchronous or synchronous, you will stay with the prefixes 
once you've added them. Which not only guarantees that async/await devolves 
into true co-routines, but it also gurantees that they proliferate everything 
and once they're in, they're never going out.

And that's why it isn't an argument.

On Sun, Feb 26, 2017 at 12:05 PM, Alexander Jones mailto:a...@weej.com]> wrote:

Florian, you shouldn't pass the argument of explicit vs implicit coroutines off 
as being so simple. There are many compelling arguments for both! Please Google 
them!


On Sun, 26 Feb 2017 at 00:01, Florian Bösch mailto:pya...@gmail.com]> wrote:

On Sat, Feb 25, 2017 at 11:55 PM, Codefined mailto:codefi...@debenclipper.com]> wrote:

This seems to be so very confusing for anybody new studying this language, 
almost everyone I talk to gets stuck up on some part of it.
Promises are bad, and mixing them with async/await is worse. Should never have 
been added to any kind of standard.
async function asyncFunction() { let [err, data] = await asyncFunction() }
function asyncFunction(){
  return otherAsyncFunction();
}

Even simpler, you'd just need co-routines.
___
es-discuss mailing list
es-discuss@mozilla.org [mailto:es-discuss@mozilla.org]
https://mail.mozilla.org/listinfo/es-discuss 
[https://mail.mozilla.org/listinfo/es-discuss]

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Enable async/await to work on functions that don't just return promises.

2017-02-26 Thread Florian Bösch
On Sun, Feb 26, 2017 at 2:08 PM, Jerald Cohen 
wrote:

> (although, at the moment, I fail to see why one can't just use a normal
> "return").
>

You're probably unaware of this, but there is a fixation in this community,
and many adjacent ones, that if you sprinkle syntax magic dust atop
co-routines, it fixes issues of concurrency (it doesn't). But in a
nutshell, that's why you can't just use a normal "return".
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Enable async/await to work on functions that don't just return promises.

2017-02-26 Thread Florian Bösch
ees that async/await devolves into true co-routines, but it also
> gurantees that they proliferate everything and once they're in, they're
> never going out.
>
> And that's why it isn't an argument.
>
> On Sun, Feb 26, 2017 at 12:05 PM, Alexander Jones  wrote:
>
>> Florian, you shouldn't pass the argument of explicit vs implicit
>> coroutines off as being so simple. There are many compelling arguments for
>> both! Please Google them!
>>
>>
>> On Sun, 26 Feb 2017 at 00:01, Florian Bösch  wrote:
>>
>>> On Sat, Feb 25, 2017 at 11:55 PM, Codefined 
>>> wrote:
>>>
>>> This seems to be so very confusing for anybody new studying this
>>> language, almost everyone I talk to gets stuck up on some part of it.
>>>
>>> Promises are bad, and mixing them with async/await is worse. Should
>>> never have been added to any kind of standard.
>>>
>>> async function asyncFunction() {let [err, data] = await asyncFunction()
>>> }
>>>
>>> function asyncFunction(){
>>>   return otherAsyncFunction();
>>> }
>>>
>>> Even simpler, you'd just need co-routines.
>>> ___
>>> 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: Enable async/await to work on functions that don't just return promises.

2017-02-26 Thread Jerald Cohen
I actually really like this idea.  It reminds me of the C# syntax to try to
accomplish the same thing.  Although under the bonnet C# uses "tasks",
which appear to be their form of promises, the surface code does look very
similar, take for example:

public async Task MyMethodAsync(){
Task longRunningTask = LongRunningOperationAsync();
// independent work which doesn't need the result of
LongRunningOperationAsync can be done here

//and now we call await on the task
int result = await longRunningTask;
//use the result
Console.WriteLine(result);}
public async Task LongRunningOperationAsync() // assume we return
an int from this long running operation {
await Task.Delay(1000); //1 seconds delay
return 1;}

Taken from this stackoverflow question
<http://stackoverflow.com/questions/14455293/how-and-when-to-use-async-and-await>.
I would be completely in support of shifting async/await from requiring
promises and instead allowing just the ability to use semi-normal "async
returns" (although, at the moment, I fail to see why one can't just use a
normal "return").

On Sun, Feb 26, 2017 at 12:43 PM, Florian Bösch  wrote:

> It would be nice if there even was an argument, but there isn't. There
> isn't because async/await naturally devolves into implicit coroutines, so
> any argument would be moot.
>
> To illustrate, suppose you have these 4 functions:
>
> let a = function(){
>   return b();
> }
>
> let b = function(){
>   return c();
> }
>
> let c = function(){
>return d();
> }
>
> let d = function(){
>   return whatever();
> }
>
>
> Call chains like this are typical. It's the staple of software engineering
> (for reasons of proper separation of concerns, reuse of utility code,
> etc.). If you believe that there is an argument about this being exemplary,
> it would be impossible to have an argument with you about software
> engineering at all. Of course real-world examples are more complex and
> don't just return whatever the underlying function produced, but as a
> control flow example it suffices. These chains are often much deeper than 4
> levels, it's not uncommon to encounter call chains 10, 15, 20 or 30 layers
> deep.
>
> Now let's suppose you figure that function d wants to do something
> asynchronous.
>
> So you go and do:
>
> let d = function(){
>   return xhr();
> }
>
>
> But of course that doesn't work, because d is not async. So you go and do:
>
> let d = async function(){
>   return await xhr();
> }
>
> Of course that doesn't work because c is not async, and so forth, so
> eventually your code looks like that.
>
> let a = async function(){
>   return await b();
> }
>
> let b = async function(){
>   return await c();
> }
>
> let c = async function(){
>return await d();
> }
>
> let d = async function(){
>   return await xhr();
> }
>
>
> In essence, you've applied to following two regular expression:
> s/function/await function/g and s/.+?\(\)/await ()/ . Of course that'd be
> horrid to do, so in reality you'd please use a proper JS parser. How did
> your code look before you applied these regular expressions? Well, it looks
> exactly like at the start.
>
> let a = function(){
>   return b();
> }
>
> let b = function(){
>   return c();
> }
>
> let c = function(){
>return d();
> }
>
> let d = function(){
>   return xhr();
> }
>
>
> But it isn't like at the start, because now it can trigger race conditions
> and is asynchronous. It is in fact now idempotent with true co-routines,
> except some unnecessary code transmoglification.
>
> This conclusively proves that await/async is an inconvenient clutch that
> naturally devolves into true co-routines. Now you might try to argue, that
> real-world code isn't just going to prefix every function call with await
> and every function body with async and stay that way.
>
> However, this would be in invalid argument for actual real-world code,
> because. People don't just constantly switch back and forth and re-engineer
> their code just because they want something async to happen underneath. You
> don't go and bicycle repair every call and function definition if you
> should decide to toggle synchronous or asynchronous. Therefore, since
> prefixing everything works no matter if it is asynchronous or synchronous,
> you will stay with the prefixes once you've added them. Which not only
> guarantees that async/await devolves into true co-routines, but it also
> gurantees that they proliferate everything and once they're in, they're
> never going out.
>
&g

Re: Enable async/await to work on functions that don't just return promises.

2017-02-26 Thread Florian Bösch
It would be nice if there even was an argument, but there isn't. There
isn't because async/await naturally devolves into implicit coroutines, so
any argument would be moot.

To illustrate, suppose you have these 4 functions:

let a = function(){
  return b();
}

let b = function(){
  return c();
}

let c = function(){
   return d();
}

let d = function(){
  return whatever();
}


Call chains like this are typical. It's the staple of software engineering
(for reasons of proper separation of concerns, reuse of utility code,
etc.). If you believe that there is an argument about this being exemplary,
it would be impossible to have an argument with you about software
engineering at all. Of course real-world examples are more complex and
don't just return whatever the underlying function produced, but as a
control flow example it suffices. These chains are often much deeper than 4
levels, it's not uncommon to encounter call chains 10, 15, 20 or 30 layers
deep.

Now let's suppose you figure that function d wants to do something
asynchronous.

So you go and do:

let d = function(){
  return xhr();
}


But of course that doesn't work, because d is not async. So you go and do:

let d = async function(){
  return await xhr();
}

Of course that doesn't work because c is not async, and so forth, so
eventually your code looks like that.

let a = async function(){
  return await b();
}

let b = async function(){
  return await c();
}

let c = async function(){
   return await d();
}

let d = async function(){
  return await xhr();
}


In essence, you've applied to following two regular expression:
s/function/await function/g and s/.+?\(\)/await ()/ . Of course that'd be
horrid to do, so in reality you'd please use a proper JS parser. How did
your code look before you applied these regular expressions? Well, it looks
exactly like at the start.

let a = function(){
  return b();
}

let b = function(){
  return c();
}

let c = function(){
   return d();
}

let d = function(){
  return xhr();
}


But it isn't like at the start, because now it can trigger race conditions
and is asynchronous. It is in fact now idempotent with true co-routines,
except some unnecessary code transmoglification.

This conclusively proves that await/async is an inconvenient clutch that
naturally devolves into true co-routines. Now you might try to argue, that
real-world code isn't just going to prefix every function call with await
and every function body with async and stay that way.

However, this would be in invalid argument for actual real-world code,
because. People don't just constantly switch back and forth and re-engineer
their code just because they want something async to happen underneath. You
don't go and bicycle repair every call and function definition if you
should decide to toggle synchronous or asynchronous. Therefore, since
prefixing everything works no matter if it is asynchronous or synchronous,
you will stay with the prefixes once you've added them. Which not only
guarantees that async/await devolves into true co-routines, but it also
gurantees that they proliferate everything and once they're in, they're
never going out.

And that's why it isn't an argument.

On Sun, Feb 26, 2017 at 12:05 PM, Alexander Jones  wrote:

> Florian, you shouldn't pass the argument of explicit vs implicit
> coroutines off as being so simple. There are many compelling arguments for
> both! Please Google them!
>
>
> On Sun, 26 Feb 2017 at 00:01, Florian Bösch  wrote:
>
>> On Sat, Feb 25, 2017 at 11:55 PM, Codefined 
>> wrote:
>>
>> This seems to be so very confusing for anybody new studying this
>> language, almost everyone I talk to gets stuck up on some part of it.
>>
>> Promises are bad, and mixing them with async/await is worse. Should never
>> have been added to any kind of standard.
>>
>> async function asyncFunction() {let [err, data] = await asyncFunction()
>> }
>>
>> function asyncFunction(){
>>   return otherAsyncFunction();
>> }
>>
>> Even simpler, you'd just need co-routines.
>> ___
>> 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: Enable async/await to work on functions that don't just return promises.

2017-02-26 Thread Alexander Jones
Florian, you shouldn't pass the argument of explicit vs implicit coroutines
off as being so simple. There are many compelling arguments for both!
Please Google them!


On Sun, 26 Feb 2017 at 00:01, Florian Bösch  wrote:

> On Sat, Feb 25, 2017 at 11:55 PM, Codefined 
> wrote:
>
> This seems to be so very confusing for anybody new studying this language,
> almost everyone I talk to gets stuck up on some part of it.
>
> Promises are bad, and mixing them with async/await is worse. Should never
> have been added to any kind of standard.
>
> async function asyncFunction() {let [err, data] = await asyncFunction()
> }
>
> function asyncFunction(){
>   return otherAsyncFunction();
> }
>
> Even simpler, you'd just need co-routines.
> ___
> 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: Enable async/await to work on functions that don't just return promises.

2017-02-26 Thread Codefined
Hello Isiah,

I'm not sure you understand my point on why this is important.  Although if you 
understand all the concepts used here it's logical, it's very intimidating to a 
person newer to Javascript.  This could be especially true in a framework like 
Node.JS, where you can run into a situation like this in your first program 
(for example, reading/writing to a file using promises).  Take:
function asyncFunction() { return new Promise(resolve => { someAsync('data', 
(...args) => resolve(args)) }) }
Here you have to explain the concept of returning a promise, anonymous 
functions, array decomposition and what resolving does.  Remember that this 
could be required to just write to a file. However, if one was to explain:
function asyncFunction() { someAsync('data', data => { async return data }) }
Then one only has to talk about anonymous functions and how `async return` 
works.  You say in your second point you'll need to learn promises anyway, but 
you can delay learning about them for a very long time.  I'm struggling to 
think of a simple program that requires the use of promises over this syntax.  
People are able to use things without needing to know how the internal 
components.  For example, I don't know even vaguely how `bcrypt` works under 
the surface but I still use it in almost every project I work on.  I'm sure you 
can think of similar examples where you don't know the exact implementation of 
something but still use it often without forgetting the necessary syntax (like 
`await`)..

And I'm afraid I have to completely disagree with your third point.  The 
concepts are very complicated to a beginner, especially considering how many 
different concepts you have to learn at once within just your first couple of 
programs.  We're talking about learning 3-4 new concepts things in just 5 lines 
of a program that wouldn't be out of place as the third or fourth program you 
wrote.
On 26/02/2017 00:15:14, Isiah Meadows  wrote:
Here's my thoughts:

1. There's minimal benefit to be gained with your example, since it
can already be simulated very similarly with the current API:

function asyncFunction() {
return new Promise(resolve => {
someAsync('data', (...args) => resolve(args))
})
}

2. This won't alleviate you of the need to learn promises anyways, and
in general, when you're working with async code, you *should* learn
the Promise APIs. Otherwise, `async` functions won't make much sense
to you, and you're liable to forget an `await` when you needed one.

3. The concepts aren't really that complicated. It's already easy to
explain as an asynchronous `return` or `throw`, just they aren't
syntactic at the start because you can't return from a function in a
callback.[1] You don't have to explain monadic `join` or `bind` just
to explain how a promise works.

[1] Kotlin is an exception here, in that it allows explicitly
non-local jumps, provided they're correctly typed.

-

Isiah Meadows
m...@isiahmeadows.com


On Sat, Feb 25, 2017 at 5:55 PM, Codefined wrote:
> It strikes me as an interesting development to see that the current
> definition of Async/Await (as I see it), is just simple syntactic sugar for
> `.then()`. While I, to an extent, see the point of such a command as being
> useful, I remain unaware of the exact reasoning why we need to include
> promises in the first place. Wouldn't it be so much more powerful to be
> able to use completely normal syntax, as you would in synchronous code as
> well as the option of promise chains?
>
> For example, take the following code snippet:
>
> async function asyncFunction() {
> return new Promise((resolve, reject) => {
> someAsync('data', (err, data) => {
> if (err) {
> reject(err); return;
> }
> resolve(data);
> });
> });
> }
>
> This seems to be so very confusing for anybody new studying this language,
> almost everyone I talk to gets stuck up on some part of it. Wouldn't it be
> so very beautiful if we could just do:
>
> async function asyncFunction() {
> someAsync('data', (err, data) => {
> async return [err, data]
> })
> }
>
> When we call this with the `await` keyword, we simply `await` a return. No
> special promises or extra keywords needed, everything works as you would
> expect it to. This also has the benefit of shortening our required code
> from 10 lines to 5 lines, removing a significant proportion of boilerplate
> code.
>
> async function asyncFunction() {
> let [err, data] = await asyncFunction()
> }
>
> Some interesting counterpoints to consider from the #node.js channel on
> freenode
> - "Doesn't this just add complexity to the specification?"
> + Yes, it does mean that people who wi

Re: Enable async/await to work on functions that don't just return promises.

2017-02-25 Thread Isiah Meadows
Here's my thoughts:

1. There's minimal benefit to be gained with your example, since it
can already be simulated very similarly with the current API:

function asyncFunction() {
return new Promise(resolve => {
someAsync('data', (...args) => resolve(args))
})
}

2. This won't alleviate you of the need to learn promises anyways, and
in general, when you're working with async code, you *should* learn
the Promise APIs. Otherwise, `async` functions won't make much sense
to you, and you're liable to forget an `await` when you needed one.

3. The concepts aren't really that complicated. It's already easy to
explain as an asynchronous `return` or `throw`, just they aren't
syntactic at the start because you can't return from a function in a
callback.[1] You don't have to explain monadic `join` or `bind` just
to explain how a promise works.

[1] Kotlin is an exception here, in that it allows explicitly
non-local jumps, provided they're correctly typed.

-

Isiah Meadows
m...@isiahmeadows.com


On Sat, Feb 25, 2017 at 5:55 PM, Codefined  wrote:
> It strikes me as an interesting development to see that the current
> definition of Async/Await (as I see it), is just simple syntactic sugar for
> `.then()`.  While I, to an extent, see the point of such a command as being
> useful, I remain unaware of the exact reasoning why we need to include
> promises in the first place.  Wouldn't it be so much more powerful to be
> able to use completely normal syntax, as you would in synchronous code as
> well as the option of promise chains?
>
> For example, take the following code snippet:
>
> async function asyncFunction() {
>   return new Promise((resolve, reject) => {
> someAsync('data', (err, data) => {
>   if (err) {
> reject(err); return;
>   }
>   resolve(data);
> });
>   });
> }
>
> This seems to be so very confusing for anybody new studying this language,
> almost everyone I talk to gets stuck up on some part of it.  Wouldn't it be
> so very beautiful if we could just do:
>
> async function asyncFunction() {
> someAsync('data', (err, data) => {
> async return [err, data]
> })
> }
>
> When we call this with the `await` keyword, we simply `await` a return.  No
> special promises or extra keywords needed, everything works as you would
> expect it to.  This also has the benefit of shortening our required code
> from 10 lines to 5 lines, removing a significant proportion of boilerplate
> code.
>
> async function asyncFunction() {
> let [err, data] = await asyncFunction()
> }
>
> Some interesting counterpoints to consider from the #node.js channel on
> freenode
>  - "Doesn't this just add complexity to the specification?"
>+ Yes, it does mean that people who wish to implement Javascript will
> have to spend longer implementing await/async.  However, in my opinion it's
> a better solution that forcing everyone who wishes to use async/await to
> also learn how to use `new Promise()` and what the `reject()` and
> `resolve()` do.  Due to how often you have to deal with asynchronous code in
> Javascript, often people come across this issue very early on in learning
> the language, making is as easy as adding an extra `async` before your
> return statement seems like an acceptable exchange.
>  - "Why not just automatically promisify functions using a library like
> bluebird?"
>+ Similar to the previous question, I honestly feel that forcing people
> to learn the API for yet another library in order to be able to do such a
> simple task is much more taxing than in this method.
>  - "I just don't like the async return"
>+ Originally it was just a return, but a friend pointed out this ran into
> issues that it would simply return from the last function.  What I thought
> would be much easier was some sort of keyword that makes it return from the
> async function, instead of any other functions.  To me, `async` came
> naturally, but this is just my first suggestion on the future of Javascript,
> and I'd be interested to know if you have any better suggestions.
>
> ___
> 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: Enable async/await to work on functions that don't just return promises.

2017-02-25 Thread Florian Bösch
On Sat, Feb 25, 2017 at 11:55 PM, Codefined 
wrote:

> This seems to be so very confusing for anybody new studying this language,
> almost everyone I talk to gets stuck up on some part of it.
>
Promises are bad, and mixing them with async/await is worse. Should never
have been added to any kind of standard.
>
> async function asyncFunction() {let [err, data] = await asyncFunction()
> }
>
> function asyncFunction(){
  return otherAsyncFunction();
}

Even simpler, you'd just need co-routines.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Enable async/await to work on functions that don't just return promises.

2017-02-25 Thread Codefined
It strikes me as an interesting development to see that the current definition 
of Async/Await (as I see it), is just simple syntactic sugar for `.then()`.  
While I, to an extent, see the point of such a command as being useful, I 
remain unaware of the exact reasoning why we need to include promises in the 
first place.  Wouldn't it be so much more powerful to be able to use completely 
normal syntax, as you would in synchronous code as well as the option of 
promise chains?
For example, take the following code snippet:
async function asyncFunction() { return new Promise((resolve, reject) => { 
someAsync('data', (err, data) => { if (err) { reject(err); return; } 
resolve(data); }); }); }
This seems to be so very confusing for anybody new studying this language, 
almost everyone I talk to gets stuck up on some part of it.  Wouldn't it be so 
very beautiful if we could just do:
async function asyncFunction() { someAsync('data', (err, data) => { async 
return [err, data] }) }
When we call this with the `await` keyword, we simply `await` a return.  No 
special promises or extra keywords needed, everything works as you would expect 
it to.  This also has the benefit of shortening our required code from 10 lines 
to 5 lines, removing a significant proportion of boilerplate code.  
async function asyncFunction() { let [err, data] = await asyncFunction() }
Some interesting counterpoints to consider from the #node.js channel on freenode
 - "Doesn't this just add complexity to the specification?"
   + Yes, it does mean that people who wish to implement Javascript will have 
to spend longer implementing await/async.  However, in my opinion it's a better 
solution that forcing everyone who wishes to use async/await to also learn how 
to use `new Promise()` and what the `reject()` and `resolve()` do.  Due to how 
often you have to deal with asynchronous code in Javascript, often people come 
across this issue very early on in learning the language, making is as easy as 
adding an extra `async` before your return statement seems like an acceptable 
exchange.
 - "Why not just automatically promisify functions using a library like 
bluebird?"
   + Similar to the previous question, I honestly feel that forcing people to 
learn the API for yet another library in order to be able to do such a simple 
task is much more taxing than in this method.
 - "I just don't like the async return"
   + Originally it was just a return, but a friend pointed out this ran into 
issues that it would simply return from the last function.  What I thought 
would be much easier was some sort of keyword that makes it return from the 
async function, instead of any other functions.  To me, `async` came naturally, 
but this is just my first suggestion on the future of Javascript, and I'd be 
interested to know if you have any better suggestions.___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Cancel Promise pattern (no cancellable promises)

2017-01-12 Thread Isiah Meadows
And that's why we're waiting on the next meeting to happen with notes
posted, so we can figure out what to do next. It's likely to get discussed,
especially considering the current situation and pressing need for it.

On Thu, Jan 12, 2017, 13:27 Jordan Harband  wrote:

> The Cancellable Promises proposal itself is currently withdrawn, but don't
> forget that all of the previous discussion on cancellation in promises led
> to that proposal.
>
> It would be shortsighted to pretend they don't exist, or that the spec
> proposal won't matter forever to any other cancellation proposal, and doing
> so won't help any alternative proposal.
>
> On Thu, Jan 12, 2017 at 7:44 AM, Jan-Ivar Bruaroey 
> wrote:
>
> Cancellable promises is dead. Please don't hijack this thread discussing
> them.
>
> Thanks,
>
> .: Jan-Ivar :.
>
>
> ___
> 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: Cancel Promise pattern (no cancellable promises)

2017-01-12 Thread Jordan Harband
The Cancellable Promises proposal itself is currently withdrawn, but don't
forget that all of the previous discussion on cancellation in promises led
to that proposal.

It would be shortsighted to pretend they don't exist, or that the spec
proposal won't matter forever to any other cancellation proposal, and doing
so won't help any alternative proposal.

On Thu, Jan 12, 2017 at 7:44 AM, Jan-Ivar Bruaroey  wrote:

> Cancellable promises is dead. Please don't hijack this thread discussing
> them.
>
> Thanks,
>
> .: Jan-Ivar :.
>
>
> ___
> 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: Cancel Promise pattern (no cancellable promises)

2017-01-12 Thread Jan-Ivar Bruaroey
Cancellable promises is dead. Please don't hijack this thread discussing 
them.


Thanks,

.: Jan-Ivar :.

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Cancel Promise pattern (no cancellable promises)

2017-01-10 Thread Igor Baklan
Check on practice hove [bluebirdjs-cancellation](
http://bluebirdjs.com/docs/api/cancellation.html) works and find out that
[promise-executor](
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise#Parameters).``onCancel``
callback get executed before finally blocks of all affected promises, so
potential api for overriding default cancellation delivery mechanism/"rail"
(success/failure/cancellation) might exist still however I can not see them
in bluebirdjs documentation.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Cancel Promise pattern (no cancellable promises)

2017-01-10 Thread Igor Baklan
> Um... This isn't much different than Bluebird's
`Promise.prototype.cancel`,
> admittedly the least optimal of all these so far.

Yes, very similar, in that it is propagated upward on "async-stacktrace",
and can be actually handled in [promise-executor](
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise#Parameters).
But very different in a way how callbacks of "affected" promises should be
treated. As I can understand from [bluebirdjs-cancellation](
http://bluebirdjs.com/docs/api/cancellation.html) article - on cancellation
method invocation it always go into cancellation action (which is delivered
on that "3-rd rail", so no success neither failure callbacks are invoked
but consistency still preserved - finally callbacks still executed - which
is really nice option but ...). But what I say in this "interruption" idea,
that it should be up to [promise-executor](
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise#Parameters)
what action should be taken on underlying promise (and in turn propagated
downward async-stacktrace). So that when you call
here ``somePromice.interrupt(someInterruptionConfig)`` it may end up with
any kind of results - success/failure/3rd-rail-cancellation - and it should
be specified in particular [promise-executor](
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise#Parameters)
(generally in top-most promise in async-stacktrace) how to react on this
particular ``someInterruptionConfig`` passed into ``.interrupt(...)``
method. However I should admit that most likely "implementers" and "users"
of such functionality would prefer and intent exactly that behavior from
[bluebirdjs-cancellation](http://bluebirdjs.com/docs/api/cancellation.html)
, and would rather want always implement that kind of behavior by default,
but what I actually don't like from that - is that decision "how to
complete underlying/topmost-interrupted promise" is taking without "asking
[promise-executor](
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise#Parameters)
what it thinks about it before(not after) canceling" (whether it "objects"
this abrupt execution, maybe it prefers to continue working and just ignore
this interruption signal, or may be it already has some default
success/failure result and would prefers to complete abruptly but with its
own default result etc).

So again what is not very good with [bluebirdjs-cancellation](
http://bluebirdjs.com/docs/api/cancellation.html), that [promise-executor](
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise#Parameters)
can not intercept this signal, and can not "preventDefault"-behavior, but
instead it is only notified that "everything(cancellation) already
happened" (as I can conclude from [bluebirdjs-cancellation](
http://bluebirdjs.com/docs/api/cancellation.html))

And finally, I think it is also very nice to have that cancellation with
"firm contracts" - which always/unavoidably cancels promises chain (for
example by the means of that 3-rd-cancellation-rail). But as for me it
would be also good to have that more "soft" functionality which delegates
to [promise-executor](
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise#Parameters)
decision on which "rail" (success/failure/cancellation) and with which
actual "value" deliver that abnormal execution completion / cancellation.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Cancel Promise pattern (no cancellable promises)

2017-01-09 Thread Isiah Meadows
Um... This isn't much different than Bluebird's `Promise.prototype.cancel`,
admittedly the least optimal of all these so far.

On Sat, Jan 7, 2017, 08:02 Igor Baklan  wrote:

> In general I thing it would be good to have something like
> [``java``(``Thread.interrupt()``)](
> https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#interrupt()),
> assuming that "Thread" here can be "async stacktrace of promises", and
> interrupt notification should be just forwarded to top entry
> ([promise-executor](
> https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise#Parameters))
> and handled there arbitrary. In meta code it can be approximately expressed
> like  ``promise.interrupt(interruption_config)`` ==>
> ``promise.topPromiseInAwaitChain().injectInterruptionNotification(interruption_config)``.
> So it should be up to [promise-executor](
> https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise#Parameters)
> - whether it want to complete abnormally on interruption (either with
> success or with failure), or just ignore this signal and continue execution
> without any reaction. It just assumes that general ``.then(...)``-like
> promises or ``async (...)  => {...}``-like promises should propagate
> interruption-signal transparently upward over async-stacktrace, and
> interruption-signal would be handled only in promises with executors which
> aware of interruption capability. In code it may look like
>
> ```js
> const waitAsync = (delay) => (new Promise(
>   (resOk, resErr, interuptionSignalEmitter) => {
> const beforeComplete = () => {clearTimeout(tid);}
> const tid = setTimeout(
>   () => {beforeComplete(); resOk();},
>   delay
> );
> interuptionSignalEmitter.on(
>   (interuptionConfig) => {
> beforeComplete();
> if (interuptionConfig && interuptionConfig.raiseError) {
>   resErr(new Error("abnormal interuption"));
> } else {
>   resOk();
> }
>   }
> );
>   }
> ));
>
> // waitAsync(100).then(() => {console.log("wait ok")}).interrupt() -
> should complete successfully
> //   ("wait ok" message should be printed) but without delay in 100ms
> // waitAsync(100).then(() => {console.log("wait
> ok")}).interrupt({raiseError: true}) - should complete with failure
> //   (NO "wait ok" message should be printed) and without delay in 100ms
> ```
>
>
> So, in other words, I would rather say, that we lack something like event
> capturing pahase when we intent for abnormal-completion/cancellation. I
> mean, if we have for example some async-stacktrace and some particular
> entry in it in the middle (some running and not yet completed promise),
> then it looks very natural that we may wish to "send a signal/message"
> downward over async-stacktrace, it just can be made by throwing something
> in that entry (and that "thrown something" will be naturally propagated
> downward async-stacktrace/promises-chain). But in certain cases we may need
> to "send a signal/message" upward over async-stacktrace which should
> generally end up by handling in very top promise executor (and if that
> top-most promise in chain decide to complete execution abnormally, then all
> clean-up in promises-chain also happens "abnormally"), while if we just
> "unsubscribe" some middle entry form it's "natural parent" and "abnormally"
> assign some result to that entry, then ofcourse, all cleanup in "upper
> part" of async-stacktrace will happen later (which ofcourse also can be
> desired behavior in some cases).
>
> Jan-Ivar Bruaroey wrote:
> > Because it doesn't make fetch stop fetching, which is what people want
> > as I understand it (to not have the fetch keep going even though they've
> stopped waiting for it).
>
> Completely agree, but I would rather prefer
>
> ```js
> fetch(someUrl, someConfig).interuptOn(interruptionToken)
> ```
> vs
> ```js
> fetch(someUrl, {...someConfig, cancel: interruptionToken)
> ```
> in this case ``.interruptOn`` can be easily defined on top of
> ``.interrupt`` like ``promise.interruptOn(interruptionReasonToken)`` <==>
> ``interruptionReasonToken.then((reason) => {promise.interrupt(reason)}),
> promise``
>
>
> Bergi wrote:
> > Yes, that's what I mean. Sure, I could use `Promise.race` to get the
> > cancellation even if the non-cancellable operation resumes, but that's
> > quite ugly:
> >
> > Promise.race([
> >  promise()
> >  …c

Re: Cancel Promise pattern (no cancellable promises)

2017-01-07 Thread Igor Baklan
In general I thing it would be good to have something like
[``java``(``Thread.interrupt()``)](
https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#interrupt()),
assuming that "Thread" here can be "async stacktrace of promises", and
interrupt notification should be just forwarded to top entry
([promise-executor](
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise#Parameters))
and handled there arbitrary. In meta code it can be approximately expressed
like  ``promise.interrupt(interruption_config)`` ==>
``promise.topPromiseInAwaitChain().injectInterruptionNotification(interruption_config)``.
So it should be up to [promise-executor](
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise#Parameters)
- whether it want to complete abnormally on interruption (either with
success or with failure), or just ignore this signal and continue execution
without any reaction. It just assumes that general ``.then(...)``-like
promises or ``async (...)  => {...}``-like promises should propagate
interruption-signal transparently upward over async-stacktrace, and
interruption-signal would be handled only in promises with executors which
aware of interruption capability. In code it may look like

```js
const waitAsync = (delay) => (new Promise(
  (resOk, resErr, interuptionSignalEmitter) => {
const beforeComplete = () => {clearTimeout(tid);}
const tid = setTimeout(
  () => {beforeComplete(); resOk();},
  delay
);
interuptionSignalEmitter.on(
  (interuptionConfig) => {
beforeComplete();
if (interuptionConfig && interuptionConfig.raiseError) {
  resErr(new Error("abnormal interuption"));
} else {
  resOk();
}
  }
);
  }
));

// waitAsync(100).then(() => {console.log("wait ok")}).interrupt() - should
complete successfully
//   ("wait ok" message should be printed) but without delay in 100ms
// waitAsync(100).then(() => {console.log("wait
ok")}).interrupt({raiseError: true}) - should complete with failure
//   (NO "wait ok" message should be printed) and without delay in 100ms
```


So, in other words, I would rather say, that we lack something like event
capturing pahase when we intent for abnormal-completion/cancellation. I
mean, if we have for example some async-stacktrace and some particular
entry in it in the middle (some running and not yet completed promise),
then it looks very natural that we may wish to "send a signal/message"
downward over async-stacktrace, it just can be made by throwing something
in that entry (and that "thrown something" will be naturally propagated
downward async-stacktrace/promises-chain). But in certain cases we may need
to "send a signal/message" upward over async-stacktrace which should
generally end up by handling in very top promise executor (and if that
top-most promise in chain decide to complete execution abnormally, then all
clean-up in promises-chain also happens "abnormally"), while if we just
"unsubscribe" some middle entry form it's "natural parent" and "abnormally"
assign some result to that entry, then ofcourse, all cleanup in "upper
part" of async-stacktrace will happen later (which ofcourse also can be
desired behavior in some cases).

Jan-Ivar Bruaroey wrote:
> Because it doesn't make fetch stop fetching, which is what people want
> as I understand it (to not have the fetch keep going even though they've
stopped waiting for it).

Completely agree, but I would rather prefer

```js
fetch(someUrl, someConfig).interuptOn(interruptionToken)
```
vs
```js
fetch(someUrl, {...someConfig, cancel: interruptionToken)
```
in this case ``.interruptOn`` can be easily defined on top of
``.interrupt`` like ``promise.interruptOn(interruptionReasonToken)`` <==>
``interruptionReasonToken.then((reason) => {promise.interrupt(reason)}),
promise``


Bergi wrote:
> Yes, that's what I mean. Sure, I could use `Promise.race` to get the
> cancellation even if the non-cancellable operation resumes, but that's
> quite ugly:
>
> Promise.race([
>  promise()
>  …chain…,
>  cancelToken
> ]).then(callback);
>
> especially when you'll need to nest that pattern. Instead, I'd just like
> to write
>
> promise()
> …chain…
> .then(callback, cancelToken)
>
> with the same behaviour.

Very reasonable. left-to-right ``.`` chaining is much more readable and
concise then wrap-like expression chaining.
But I would rather put ``cancelToken`` somewhere else, not in ``.then``
call.
>From my perspective it can look like

```js
Promise.race([
 promise()
 …chain…,
 cancelToken
]).then(callback);
```
<==>
```js
promise() …chain… cancellable().cancelOn(canc

Re: Cancel Promise pattern (no cancellable promises)

2017-01-04 Thread Jan-Ivar Bruaroey

Happy New Year!

Here's a cleanup iteration on this proposal: 
http://jsfiddle.net/jib1/wyq4sxsc/


You need Chrome or Firefox Developer Edition to run it due to async/await.

I've renamed the error to "CancelError" and made cancellation always 
fail with it, removing the "resumption" option.


PTAL!

Some comments on the earlier thread here:
 - The above fiddle suffers no accumulative "memory leak" problems. GC 
just works.
 - Synchronous inspection is necessary in multi-threaded cancellation 
only, not JS.


.: Jan-Ivar :.

On 10/26/16 10:41 PM, Jan-Ivar Bruaroey wrote:
This is an alternative to cancellable promises that relies entirely on 
existing JavaScript.


I'm posting this here in hopes to bring the discussion back to 
practical use cases and minimal needs.


Example:

Here's a setTimeout wrapper with cancellation, using a regular promise 
as a cancellation token.


let wait = (ms, cancel) => {
  let id;
  return Promise.race([
new Promise(resolve => id = setTimeout(resolve, ms)),
(cancel || new Promise(() => {})).then(() => clearTimeout(id))
  ]);
};

function CancelledError() {
  return Object.assign(new Error("The operation was cancelled."), 
{name: "CancelledError"});

}

// Demo:

async function foo() {
  try {
let token = new Promise((r, e) => cancel.onclick = () => e(new 
CancelledError()));

await wait(500);
console.log("Wait 4 seconds...");
await wait(4000, token);
console.log("Then wait 3 more seconds...");
await wait(3000, token);
console.log("Done.");
  } catch (e) {
if (e.name != "CancelledError") throw e;
console.log("User cancelled");
  }
}
foo();


Here's the es6 version to run: http://jsfiddle.net/jib1/jz33qs32/

Things to note:
- Cancellation is targeted to specific operations (no "cancel chain" 
ambition).

- Token can be reused down the chain.
- Cancellation is propagated using a regular (new) CancellationError 
(no third rail).
- It is up to the caller whether to treat cancellations as 
non-exceptional.
- Basic Promise.race pattern works even to wrap APIs that aren't 
cancellable (stop waiting)
- Pattern allows substituting any error (though I hope we standardize 
CancelledError).
- Pattern allows chain resumption by resolving token with any desired 
value instead.


I don't think this group needs to develop much here, maybe standardize 
CancelledError, and have fetch() take a cancel promise argument like 
wait() does in the example above.


I'm open to hearing what use-cases are not be covered by this.

Looking forward to your feedback. Thanks!

.: Jan-Ivar :.


___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Cancel Promise pattern (no cancellable promises)

2016-11-01 Thread Jan-Ivar Bruaroey

On 10/31/16 2:39 PM, Herby Vojčík wrote:

Jan-Ivar Bruaroey wrote:

On 10/28/16 8:39 AM, Bergi wrote:

Jan-Ivar Bruaroey wrote:
If you try the fiddle - http://jsfiddle.net/jib1/jz33qs32/ - you'll 
see

cancelling terminates the chain. If you intersperse non-cancellable
operations, there'd be a delay if cancel is detected during those.


Yes, that's what I mean. Sure, I could use `Promise.race` to get the
cancellation even if the non-cancellable operation resumes, but that's
quite ugly:

Promise.race([
promise()
…chain…,
cancelToken
]).then(callback);

especially when you'll need to nest that pattern.


To be clear, the non-cancellable operation won't "resume" in the face of
a CancelledError. Only if the cancel happened to trigger during one of
the non-cancellable actions would there be a slight delay until that
non-cancellable operation finished (which I consider a feature) and if a
cancellable operation follows it, cancellation will happen at that 
point.


In someone can't tolerate that, then Promise.race is well-defined to do
exactly what you show, and works in harmony with this pattern. Why
reinvent the wheel?

And you'd Promise.race against the entire chain, so no need to nest this
pattern typically. This is what I mean with focusing on the minimal
use-case. Most people just want us to solve fetch already, so that
expensive network resources can be freed. To get out of the current
inertia, why not define:

fetch (url, { cancelPromise: token })


OTOH, why not to just use Promise.race directly and promote the 
pattern of "specify alternate result".

  1. This is more general;
  2. This allows creating decorators and use them like
shortcutAfter(5000, Promise.reject())(fetch(url))


Because it doesn't make fetch stop fetching, which is what people want 
as I understand it (to not have the fetch keep going even though they've 
stopped waiting for it).


.: Jan-Ivar :.

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Cancel Promise pattern (no cancellable promises)

2016-10-31 Thread Herby Vojčík



Herby Vojčík wrote:



Jan-Ivar Bruaroey wrote:

On 10/28/16 8:39 AM, Bergi wrote:

Jan-Ivar Bruaroey wrote:

If you try the fiddle - http://jsfiddle.net/jib1/jz33qs32/ - you'll see
cancelling terminates the chain. If you intersperse non-cancellable
operations, there'd be a delay if cancel is detected during those.


Yes, that's what I mean. Sure, I could use `Promise.race` to get the
cancellation even if the non-cancellable operation resumes, but that's
quite ugly:

Promise.race([
promise()
…chain…,
cancelToken
]).then(callback);

especially when you'll need to nest that pattern.


To be clear, the non-cancellable operation won't "resume" in the face of
a CancelledError. Only if the cancel happened to trigger during one of
the non-cancellable actions would there be a slight delay until that
non-cancellable operation finished (which I consider a feature) and if a
cancellable operation follows it, cancellation will happen at that point.

In someone can't tolerate that, then Promise.race is well-defined to do
exactly what you show, and works in harmony with this pattern. Why
reinvent the wheel?

And you'd Promise.race against the entire chain, so no need to nest this
pattern typically. This is what I mean with focusing on the minimal
use-case. Most people just want us to solve fetch already, so that
expensive network resources can be freed. To get out of the current
inertia, why not define:

fetch (url, { cancelPromise: token })


OTOH, why not to just use Promise.race directly and promote the pattern
of "specify alternate result".
1. This is more general;
2. This allows creating decorators and use them like
shortcutAfter(5000, Promise.reject())(fetch(url))


Well, "shortCircuitAfter" would be probably better name.


now and use this pattern, and leave the more desirable { cancel } name
for whatever future invention we hope will replace it (or annex it if
nothing better materializes)?

.: Jan-Ivar :.


Herby

___
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: Cancel Promise pattern (no cancellable promises)

2016-10-31 Thread Herby Vojčík



Jan-Ivar Bruaroey wrote:

On 10/28/16 8:39 AM, Bergi wrote:

Jan-Ivar Bruaroey wrote:

If you try the fiddle - http://jsfiddle.net/jib1/jz33qs32/ - you'll see
cancelling terminates the chain. If you intersperse non-cancellable
operations, there'd be a delay if cancel is detected during those.


Yes, that's what I mean. Sure, I could use `Promise.race` to get the
cancellation even if the non-cancellable operation resumes, but that's
quite ugly:

Promise.race([
promise()
…chain…,
cancelToken
]).then(callback);

especially when you'll need to nest that pattern.


To be clear, the non-cancellable operation won't "resume" in the face of
a CancelledError. Only if the cancel happened to trigger during one of
the non-cancellable actions would there be a slight delay until that
non-cancellable operation finished (which I consider a feature) and if a
cancellable operation follows it, cancellation will happen at that point.

In someone can't tolerate that, then Promise.race is well-defined to do
exactly what you show, and works in harmony with this pattern. Why
reinvent the wheel?

And you'd Promise.race against the entire chain, so no need to nest this
pattern typically. This is what I mean with focusing on the minimal
use-case. Most people just want us to solve fetch already, so that
expensive network resources can be freed. To get out of the current
inertia, why not define:

fetch (url, { cancelPromise: token })


OTOH, why not to just use Promise.race directly and promote the pattern 
of "specify alternate result".

  1. This is more general;
  2. This allows creating decorators and use them like
shortcutAfter(5000, Promise.reject())(fetch(url))


now and use this pattern, and leave the more desirable { cancel } name
for whatever future invention we hope will replace it (or annex it if
nothing better materializes)?

.: Jan-Ivar :.


Herby

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Cancel Promise pattern (no cancellable promises)

2016-10-31 Thread Jan-Ivar Bruaroey

On 10/28/16 8:39 AM, Bergi wrote:

Jan-Ivar Bruaroey wrote:

If you try the fiddle - http://jsfiddle.net/jib1/jz33qs32/ - you'll see
cancelling terminates the chain. If you intersperse non-cancellable
operations, there'd be a delay if cancel is detected during those.


Yes, that's what I mean. Sure, I could use `Promise.race` to get the 
cancellation even if the non-cancellable operation resumes, but that's 
quite ugly:


Promise.race([
promise()
…chain…,
cancelToken
]).then(callback);

especially when you'll need to nest that pattern.


To be clear, the non-cancellable operation won't "resume" in the face of 
a CancelledError. Only if the cancel happened to trigger during one of 
the non-cancellable actions would there be a slight delay until that 
non-cancellable operation finished (which I consider a feature) and if a 
cancellable operation follows it, cancellation will happen at that point.


In someone can't tolerate that, then Promise.race is well-defined to do 
exactly what you show, and works in harmony with this pattern. Why 
reinvent the wheel?


And you'd Promise.race against the entire chain, so no need to nest this 
pattern typically. This is what I mean with focusing on the minimal 
use-case. Most people just want us to solve fetch already, so that 
expensive network resources can be freed. To get out of the current 
inertia, why not define:


fetch (url, { cancelPromise: token })

now and use this pattern, and leave the more desirable { cancel } name 
for whatever future invention we hope will replace it (or annex it if 
nothing better materializes)?


.: Jan-Ivar :.

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Cancel Promise pattern (no cancellable promises)

2016-10-28 Thread Bergi

Jan-Ivar Bruaroey wrote:

On 10/27/16 4:25 PM, Bergi wrote:

I'd however love to be able to cancel specific chaining operations,
i.e. `then` callbacks.


If you try the fiddle - http://jsfiddle.net/jib1/jz33qs32/ - you'll see
cancelling terminates the chain. If you intersperse non-cancellable
operations, there'd be a delay if cancel is detected during those.


Yes, that's what I mean. Sure, I could use `Promise.race` to get the 
cancellation even if the non-cancellable operation resumes, but that's 
quite ugly:


Promise.race([
promise()
…chain…,
cancelToken
]).then(callback);

especially when you'll need to nest that pattern. Instead, I'd just like 
to write


promise()
…chain…
.then(callback, cancelToken)

with the same behaviour.


A crucial problem that promises don't solve is synchronous inspection.
If my operation was cancelled, I'd like to know immediately (before
starting further work) about it, instead of waiting another tick
to be notified.


I think it'd be odd to observe cancellation and not success nor failure,
so this seems orthogonal.


I meant the producer would want to observer the cancellation so that he 
doesn't attempt to resolve the promise.


But yeah, observing cancellation vs success/failure is another problem 
that would benefit from inspection. Let's say I have a cancel token and 
a promise chain. Now I want to do exactly one of three different things, 
depending on what happens first: the operation is cancelled, the promise 
is rejected, or the promise fulfills. How do I do that?



But the fundamental problem with promises as cancellation tokens is
memory leaks. In your example, if the cancel button isn't clicked for
10 seconds, the `token` promise will reference 3 `() =>
clearTimeout(id)` callbacks which close over their respective `id`s.
Three functions and three integer ids doesn't sound like much, but in
real applications with long-running un-cancelled operations a token
could accumulate quite an amount of resources which cannot be collected.
A clever programmer might make the callbacks become cheap no-ops, but
still at least the functions themselves will consume memory. For the
simple programmer, we need an automatic (not error-prone)
unsubscription mechanism once the respective cancellable operation ended.


Thanks for the links. I think I'm in the camp of not being concerned
about this. Recall I'm not proposing new functionality, just using
promises, so this stands to benefit from optimizations browsers ought to
make already, without needing special attention. Once browsers optimize:

function poll() { return isDone() || wait(1000).then(poll); }

I'll worry about this. ;)


Yeah, I just think that we *need* new functionality (like the ability to 
remove callbacks from a promise) to solve cancellation properly.


It's true that ES6 has a bug that prevents implementors from optimising 
recursive assimilation, but it's a different kettle of fish to fix that 
in the spec. I'm trying to avoid that we make the same mistake again for 
cancellation tokens, so I think you *should* be concerned.


kind regards,
 Bergi
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Cancel Promise pattern (no cancellable promises)

2016-10-27 Thread Jan-Ivar Bruaroey

On 10/27/16 4:25 PM, Bergi wrote:

But you've got some good and important points.


Thanks!


Things to note:
- Cancellation is targeted to specific operations (no "cancel chain"
ambition).


I'd however love to be able to cancel specific chaining operations, 
i.e. `then` callbacks.


If you try the fiddle - http://jsfiddle.net/jib1/jz33qs32/ - you'll see 
cancelling terminates the chain. If you intersperse non-cancellable 
operations, there'd be a delay if cancel is detected during those.



- Pattern allows chain resumption by resolving token with any desired
value instead.


I'm not sure what you mean by "resumption". And what would that value 
be used for?


Just basic Promise.race. If users were to resolve the cancel promise 
instead of rejecting it, it'd cancel the specific operation and inject a 
replacement success value instead of failing the remaining chain.


I'm not claiming it has utility, just avoiding inventing things. Perhaps:

fetch("http://flo.ra/dailyflower.png";, {cancel: wait(5000).then(() 
=> fetch("lily.png")})


A crucial problem that promises don't solve is synchronous inspection. 
If my operation was cancelled, I'd like to know immediately (before 
starting further work) about it, instead of waiting another tick

to be notified.


I think it'd be odd to observe cancellation and not success nor failure, 
so this seems orthogonal.


But the fundamental problem with promises as cancellation tokens is 
memory leaks. In your example, if the cancel button isn't clicked for 
10 seconds, the `token` promise will reference 3 `() => 
clearTimeout(id)` callbacks which close over their respective `id`s. 
Three functions and three integer ids doesn't sound like much, but in 
real applications with long-running un-cancelled operations a token 
could accumulate quite an amount of resources which cannot be collected.
A clever programmer might make the callbacks become cheap no-ops, but 
still at least the functions themselves will consume memory. For the 
simple programmer, we need an automatic (not error-prone) 
unsubscription mechanism once the respective cancellable operation ended.


Thanks for the links. I think I'm in the camp of not being concerned 
about this. Recall I'm not proposing new functionality, just using 
promises, so this stands to benefit from optimizations browsers ought to 
make already, without needing special attention. Once browsers optimize:


function poll() { return isDone() || wait(1000).then(poll); }

I'll worry about this. ;)

.: Jan-Ivar :.


Kind regards,
 Bergi

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Cancel Promise pattern (no cancellable promises)

2016-10-27 Thread Bergi

Jan-Ivar Bruaroey wrote:


I'm posting this here in hopes to bring the discussion back to practical
use cases and minimal needs.


Sorry, did we leave that somewhere? :-)

But you've got some good and important points.


Things to note:
- Cancellation is targeted to specific operations (no "cancel chain"
ambition).


I'd however love to be able to cancel specific chaining operations, i.e. 
`then` callbacks.



- Token can be reused down the chain.
- Cancellation is propagated using a regular (new) CancellationError (no
third rail).
- It is up to the caller whether to treat cancellations as non-exceptional.


Very important. I'd even go so far to let the caller only treat 
cancellations that he caused himself as non-exceptional.



- Basic Promise.race pattern works even to wrap APIs that aren't
cancellable (stop waiting)
- Pattern allows substituting any error (though I hope we standardize
CancelledError).
- Pattern allows chain resumption by resolving token with any desired
value instead.


I'm not sure what you mean by "resumption". And what would that value be 
used for?



I'm open to hearing what use-cases are not be covered by this.

Looking forward to your feedback about
using a regular promise as a cancellation token.


A crucial problem that promises don't solve is synchronous inspection. 
If my operation was cancelled, I'd like to know immediately (before 
starting further work) about it, instead of waiting another tick

to be notified.

But the fundamental problem with promises as cancellation tokens is 
memory leaks. In your example, if the cancel button isn't clicked for 10 
seconds, the `token` promise will reference 3 `() => clearTimeout(id)` 
callbacks which close over their respective `id`s. Three functions and 
three integer ids doesn't sound like much, but in real applications with 
long-running un-cancelled operations a token could accumulate quite an 
amount of resources which cannot be collected.
A clever programmer might make the callbacks become cheap no-ops, but 
still at least the functions themselves will consume memory. For the 
simple programmer, we need an automatic (not error-prone) unsubscription 
mechanism once the respective cancellable operation ended.


Kind regards,
 Bergi

--

Of course, my own proposal 
<https://github.com/bergus/promise-cancellation> is the holy grail. 
Feedback welcome :-)

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Cancel Promise pattern (no cancellable promises)

2016-10-27 Thread Jan-Ivar Bruaroey
Likely this would be more convincing without a bug. Here is the correct 
wait function:


let wait = (ms, cancel = new Promise(() => {})) => {
  let id, both = x => [x, x];
  cancel.then(...both(() => clearTimeout(id)));
  return Promise.race([new Promise(resolve => id = setTimeout(resolve, 
ms)), cancel]);

};

For caller flexibility, we want to cancel on any activity of the cancel 
promise, which would have been more apparent in an example that actually 
relied on clearTimeout working. Fiddle updated. PTAL!


.: Jan-Ivar :.

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Cancel Promise pattern (no cancellable promises)

2016-10-26 Thread Jan-Ivar Bruaroey
This is an alternative to cancellable promises that relies entirely on 
existing JavaScript.


I'm posting this here in hopes to bring the discussion back to practical 
use cases and minimal needs.


Example:

Here's a setTimeout wrapper with cancellation, using a regular promise 
as a cancellation token.


let wait = (ms, cancel) => {
  let id;
  return Promise.race([
new Promise(resolve => id = setTimeout(resolve, ms)),
(cancel || new Promise(() => {})).then(() => clearTimeout(id))
  ]);
};

function CancelledError() {
  return Object.assign(new Error("The operation was cancelled."), {name: 
"CancelledError"});
}

// Demo:

async function foo() {
  try {
let token = new Promise((r, e) => cancel.onclick = () => e(new 
CancelledError()));
await wait(500);
console.log("Wait 4 seconds...");
await wait(4000, token);
console.log("Then wait 3 more seconds...");
await wait(3000, token);
console.log("Done.");
  } catch (e) {
if (e.name != "CancelledError") throw e;
console.log("User cancelled");
  }
}
foo();


Here's the es6 version to run: http://jsfiddle.net/jib1/jz33qs32/

Things to note:
- Cancellation is targeted to specific operations (no "cancel chain" 
ambition).

- Token can be reused down the chain.
- Cancellation is propagated using a regular (new) CancellationError (no 
third rail).

- It is up to the caller whether to treat cancellations as non-exceptional.
- Basic Promise.race pattern works even to wrap APIs that aren't 
cancellable (stop waiting)
- Pattern allows substituting any error (though I hope we standardize 
CancelledError).
- Pattern allows chain resumption by resolving token with any desired 
value instead.


I don't think this group needs to develop much here, maybe standardize 
CancelledError, and have fetch() take a cancel promise argument like 
wait() does in the example above.


I'm open to hearing what use-cases are not be covered by this.

Looking forward to your feedback. Thanks!

.: Jan-Ivar :.

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Promises, async functions, and requestAnimationFrame, together.

2016-04-26 Thread Matthew Robb
This is definitely interesting stuff. Have you considered rewriting this so
that it only uses generators? If you did then you could test natively in
Chrome and see if you get the same results.


- Matthew Robb

On Sat, Apr 23, 2016 at 7:01 PM, /#!/JoePea  wrote:

> Just to show a little more detail, here's a screenshot that shows that
> the logic of the while-loop version of my animation loop fires inside
> each animation frame. I've zoomed out and we can see there's nothing
> fired between the frames:
>
>
> https://cloud.githubusercontent.com/assets/297678/14764323/c28e83cc-0968-11e6-8771-8e726158aa52.png
>
> On Sat, Apr 23, 2016 at 3:18 PM, /#!/JoePea  wrote:
> > Alright, I did an experiment, and I'm really surprised at the results!
> > Apparently, the logic (what would be drawSomething() in my previous
> > example) is fired within the frame!!
> >
> > So, let me show you my original method for starting an animation loop.
> > I'm working on a 3D project at http://infamous.io. The Scene class
> > (https://github.com/infamous/infamous/blob/master/src/motor/Scene.js)
> > has a method for starting an animation loop the standard way:
> >
> > ```js
> > async _startAnimationLoopWhenMounted() {
> > this._animationLoopStarted = true
> >
> > if (!this._mounted) await this.mountPromise
> >
> > // So now we can render after the scene is mounted.
> > const loop = timestamp => {
> > this._inFrame = true
> >
> > this._runRenderTasks(timestamp)
> > this._renderNodes(timestamp)
> >
> > // If any tasks are left to run, continue the animation loop.
> > if (this._allRenderTasks.length)
> > this._rAF = requestAnimationFrame(loop)
> > else {
> > this._rAF = null
> > this._animationLoopStarted = false
> > }
> >
> > this._inFrame = false
> > }
> >
> > this._rAF = requestAnimationFrame(loop)
> > }
> > ```
> >
> > Here's what the Chrome timeline shows for the logic that is fired
> > inside the loop:
> >
> https://cloud.githubusercontent.com/assets/297678/14764236/8eb72d4a-0965-11e6-9bb9-5db02cc23520.png
> >
> > Now, I went ahead and modified my Scene class so the method now looks
> like this:
> >
> > ```js
> > function animationFrame() {
> > let resolve = null
> > const promise = new Promise(r => resolve = r)
> > window.requestAnimationFrame(resolve)
> > return promise
> > }
> >
> > // ...
> >
> > async _startAnimationLoopWhenMounted() {
> > this._animationLoopStarted = true
> >
> > if (!this._mounted) await this.mountPromise
> >
> > this._rAF = true
> > let timestamp = null
> > while (this._rAF) {
> > timestamp = await animationFrame()
> > this._inFrame = true
> >
> > this._runRenderTasks(timestamp)
> > this._renderNodes(timestamp)
> >
> > // If any tasks are left to run, continue the animation loop.
> > if (!this._allRenderTasks.length) {
> > this._rAF = null
> > this._animationLoopStarted = false
> > }
> >
> > this._inFrame = false
> > }
> > }
> > ```
> >
> > And the timeline results are surprising! As you can see in the
> > following screenshot, all of the logic happens within the frame
> > (though you can see there's extra overhead from what I assume are the
> > extra function calls due to the fact that I'm using Facebook
> > Regenerator for the async functions):
> >
> https://cloud.githubusercontent.com/assets/297678/14764237/8eb71ce2-0965-11e6-942a-3c556c48b9a0.png
> >
> > Near the bottom right of the screen shot, you can see the tooltip as
> > I'm hovering on the call to `animationFrame` which returns the promise
> > that I am awaiting in the loop.
> >
> > Although this behavior seems to be exactly what I was hoping for, it
> > seems like there is something wrong. Could there be a bug in
> > regenerator that is failing to defer my loop code to a following tick?
> > Or is my code deferred to a following tick that somehow the animation
> > frame knows to execute within the same tick? Maybe there's something
> > I'm missing about the Promise API that allows for .then() of a promise
> > (which I assume is what Regenerator is using) to be executed in the
> > same tick? What's going on here?
> >
> > I was expecting to see the code of my loop execute outside of the
> > "Animation Frame Fired" section.
> >
> > On Sat, Apr 23, 2016 at 6:28 AM, Boris Zbarsky  wrote:
> >> On 4/23/16 4:09 AM, Salvador de la Puente González wrote:
> >>>
> >>> AFAIK, that should execute `drawSomething()` once per frame. Given a
> >>> frame is each time the animatinFrame() promise resolves.
> >>
> >>
> >> What's not obvious to me is whether it will execute it before the actual
> >> paint for the frame (i.e. before or right after the loop that's
> notifying
> >> 

Re: Promises, async functions, and requestAnimationFrame

2016-04-24 Thread Benjamin Gruenbaum
Note that there is no guarantee that the `then` handlers (after the await)
will fire in the same loop since they defer execution on their own and
might defer it further.

In practice I assume they'll probe to see if they need to actually schedule
asynchronously or the constructed promise is already handling that (like
libraries do) and won't defer it any further but that's just a guess.

The only spec I'm aware of that does not defer in this case is the
es-observable spec.

There has also been talk about being able to set the scheduler for promises
which is something I wanted to bring up in ESDiscuss but haven't been able
to yet.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Promises, async functions, and requestAnimationFrame, together.

2016-04-23 Thread /#!/JoePea
Just to show a little more detail, here's a screenshot that shows that
the logic of the while-loop version of my animation loop fires inside
each animation frame. I've zoomed out and we can see there's nothing
fired between the frames:

https://cloud.githubusercontent.com/assets/297678/14764323/c28e83cc-0968-11e6-8771-8e726158aa52.png

On Sat, Apr 23, 2016 at 3:18 PM, /#!/JoePea  wrote:
> Alright, I did an experiment, and I'm really surprised at the results!
> Apparently, the logic (what would be drawSomething() in my previous
> example) is fired within the frame!!
>
> So, let me show you my original method for starting an animation loop.
> I'm working on a 3D project at http://infamous.io. The Scene class
> (https://github.com/infamous/infamous/blob/master/src/motor/Scene.js)
> has a method for starting an animation loop the standard way:
>
> ```js
> async _startAnimationLoopWhenMounted() {
> this._animationLoopStarted = true
>
> if (!this._mounted) await this.mountPromise
>
> // So now we can render after the scene is mounted.
> const loop = timestamp => {
> this._inFrame = true
>
> this._runRenderTasks(timestamp)
> this._renderNodes(timestamp)
>
> // If any tasks are left to run, continue the animation loop.
> if (this._allRenderTasks.length)
> this._rAF = requestAnimationFrame(loop)
> else {
> this._rAF = null
> this._animationLoopStarted = false
> }
>
> this._inFrame = false
> }
>
> this._rAF = requestAnimationFrame(loop)
> }
> ```
>
> Here's what the Chrome timeline shows for the logic that is fired
> inside the loop:
> https://cloud.githubusercontent.com/assets/297678/14764236/8eb72d4a-0965-11e6-9bb9-5db02cc23520.png
>
> Now, I went ahead and modified my Scene class so the method now looks like 
> this:
>
> ```js
> function animationFrame() {
> let resolve = null
> const promise = new Promise(r => resolve = r)
> window.requestAnimationFrame(resolve)
> return promise
> }
>
> // ...
>
> async _startAnimationLoopWhenMounted() {
> this._animationLoopStarted = true
>
> if (!this._mounted) await this.mountPromise
>
> this._rAF = true
> let timestamp = null
> while (this._rAF) {
> timestamp = await animationFrame()
> this._inFrame = true
>
> this._runRenderTasks(timestamp)
> this._renderNodes(timestamp)
>
> // If any tasks are left to run, continue the animation loop.
> if (!this._allRenderTasks.length) {
> this._rAF = null
> this._animationLoopStarted = false
> }
>
> this._inFrame = false
> }
> }
> ```
>
> And the timeline results are surprising! As you can see in the
> following screenshot, all of the logic happens within the frame
> (though you can see there's extra overhead from what I assume are the
> extra function calls due to the fact that I'm using Facebook
> Regenerator for the async functions):
> https://cloud.githubusercontent.com/assets/297678/14764237/8eb71ce2-0965-11e6-942a-3c556c48b9a0.png
>
> Near the bottom right of the screen shot, you can see the tooltip as
> I'm hovering on the call to `animationFrame` which returns the promise
> that I am awaiting in the loop.
>
> Although this behavior seems to be exactly what I was hoping for, it
> seems like there is something wrong. Could there be a bug in
> regenerator that is failing to defer my loop code to a following tick?
> Or is my code deferred to a following tick that somehow the animation
> frame knows to execute within the same tick? Maybe there's something
> I'm missing about the Promise API that allows for .then() of a promise
> (which I assume is what Regenerator is using) to be executed in the
> same tick? What's going on here?
>
> I was expecting to see the code of my loop execute outside of the
> "Animation Frame Fired" section.
>
> On Sat, Apr 23, 2016 at 6:28 AM, Boris Zbarsky  wrote:
>> On 4/23/16 4:09 AM, Salvador de la Puente González wrote:
>>>
>>> AFAIK, that should execute `drawSomething()` once per frame. Given a
>>> frame is each time the animatinFrame() promise resolves.
>>
>>
>> What's not obvious to me is whether it will execute it before the actual
>> paint for the frame (i.e. before or right after the loop that's notifying
>> the animation frame callbacks completes) or whether it will do
>> drawSomething() after the paint...
>>
>> -Boris
>>
>> ___
>> 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: Promises, async functions, and requestAnimationFrame, together.

2016-04-23 Thread /#!/JoePea
Alright, I did an experiment, and I'm really surprised at the results!
Apparently, the logic (what would be drawSomething() in my previous
example) is fired within the frame!!

So, let me show you my original method for starting an animation loop.
I'm working on a 3D project at http://infamous.io. The Scene class
(https://github.com/infamous/infamous/blob/master/src/motor/Scene.js)
has a method for starting an animation loop the standard way:

```js
async _startAnimationLoopWhenMounted() {
this._animationLoopStarted = true

if (!this._mounted) await this.mountPromise

// So now we can render after the scene is mounted.
const loop = timestamp => {
this._inFrame = true

this._runRenderTasks(timestamp)
this._renderNodes(timestamp)

// If any tasks are left to run, continue the animation loop.
if (this._allRenderTasks.length)
this._rAF = requestAnimationFrame(loop)
else {
this._rAF = null
this._animationLoopStarted = false
}

this._inFrame = false
}

this._rAF = requestAnimationFrame(loop)
}
```

Here's what the Chrome timeline shows for the logic that is fired
inside the loop:
https://cloud.githubusercontent.com/assets/297678/14764236/8eb72d4a-0965-11e6-9bb9-5db02cc23520.png

Now, I went ahead and modified my Scene class so the method now looks like this:

```js
function animationFrame() {
let resolve = null
const promise = new Promise(r => resolve = r)
window.requestAnimationFrame(resolve)
return promise
}

// ...

async _startAnimationLoopWhenMounted() {
this._animationLoopStarted = true

if (!this._mounted) await this.mountPromise

this._rAF = true
let timestamp = null
while (this._rAF) {
timestamp = await animationFrame()
this._inFrame = true

this._runRenderTasks(timestamp)
this._renderNodes(timestamp)

// If any tasks are left to run, continue the animation loop.
if (!this._allRenderTasks.length) {
this._rAF = null
this._animationLoopStarted = false
}

this._inFrame = false
}
}
```

And the timeline results are surprising! As you can see in the
following screenshot, all of the logic happens within the frame
(though you can see there's extra overhead from what I assume are the
extra function calls due to the fact that I'm using Facebook
Regenerator for the async functions):
https://cloud.githubusercontent.com/assets/297678/14764237/8eb71ce2-0965-11e6-942a-3c556c48b9a0.png

Near the bottom right of the screen shot, you can see the tooltip as
I'm hovering on the call to `animationFrame` which returns the promise
that I am awaiting in the loop.

Although this behavior seems to be exactly what I was hoping for, it
seems like there is something wrong. Could there be a bug in
regenerator that is failing to defer my loop code to a following tick?
Or is my code deferred to a following tick that somehow the animation
frame knows to execute within the same tick? Maybe there's something
I'm missing about the Promise API that allows for .then() of a promise
(which I assume is what Regenerator is using) to be executed in the
same tick? What's going on here?

I was expecting to see the code of my loop execute outside of the
"Animation Frame Fired" section.

On Sat, Apr 23, 2016 at 6:28 AM, Boris Zbarsky  wrote:
> On 4/23/16 4:09 AM, Salvador de la Puente González wrote:
>>
>> AFAIK, that should execute `drawSomething()` once per frame. Given a
>> frame is each time the animatinFrame() promise resolves.
>
>
> What's not obvious to me is whether it will execute it before the actual
> paint for the frame (i.e. before or right after the loop that's notifying
> the animation frame callbacks completes) or whether it will do
> drawSomething() after the paint...
>
> -Boris
>
> ___
> 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: Promises, async functions, and requestAnimationFrame, together.

2016-04-23 Thread Boris Zbarsky

On 4/23/16 4:09 AM, Salvador de la Puente González wrote:

AFAIK, that should execute `drawSomething()` once per frame. Given a
frame is each time the animatinFrame() promise resolves.


What's not obvious to me is whether it will execute it before the actual 
paint for the frame (i.e. before or right after the loop that's 
notifying the animation frame callbacks completes) or whether it will do 
drawSomething() after the paint...


-Boris
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Promises, async functions, and requestAnimationFrame, together.

2016-04-23 Thread Salvador de la Puente González
AFAIK, that should execute `drawSomething()` once per frame. Given a frame
is each time the animatinFrame() promise resolves.

On Sat, Apr 23, 2016 at 1:38 AM, /#!/JoePea  wrote:

> Is it possible?
>
>  I thought maybe something like this:
>
> ```js
> function animationFrame() {
> let resolve = null
> const promise = new Promise(r => resolve = r)
> window.requestAnimationFrame(resolve)
> return promise
> }
>
> async function game() {
> // the game loop
> while (true) {
> await animationFrame()
> drawSomething()
> }
> }
>
> game()
> ```
>
> But, I'm not sure what to expect: does the code that follows the await
> statement execute in the frame, sometimes in the frame, or never in
> the frame? What might we expect from the various browsers?
> ___
> 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


Promises, async functions, and requestAnimationFrame, together.

2016-04-22 Thread /#!/JoePea
Is it possible?

 I thought maybe something like this:

```js
function animationFrame() {
let resolve = null
const promise = new Promise(r => resolve = r)
window.requestAnimationFrame(resolve)
return promise
}

async function game() {
// the game loop
while (true) {
await animationFrame()
drawSomething()
}
}

game()
```

But, I'm not sure what to expect: does the code that follows the await
statement execute in the frame, sometimes in the frame, or never in
the frame? What might we expect from the various browsers?
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: non-self referencial cyclical promises?

2016-02-25 Thread Benjamin Gruenbaum
Thanks​ Raul, I understand this case better now - fixed in master
https://github.com/petkaantonov/bluebird/commit/7094e1677d79de99ba5f268785f49e9d99508e2f
- wasn't particularly hard to fix this case, no one ever complained about
it or mentioned it before so it wasn't considered.

Bluebird will now raise an error about a cyclical reference here.

Native promises should have no issue fixing this without any weak maps too.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


non-self referencial cyclical promises?

2016-02-25 Thread Raul-Sebastian Mihăilă
@Benjamin: Your example is different than Bradley's. Should be:

```
var r1, p1 = new Promise(r => r1 = r);
var r2, p2 = new Promise(r => r2 = r);
```
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: non-self referencial cyclical promises?

2016-02-25 Thread Benjamin Gruenbaum
Sorry, the example fiddle was before the inclusion of bluebird - I got
confused by the UI. Here: https://jsfiddle.net/cm9kvLqv/
It appears like native chrome promises also detect it (although with a less
informative error and only for one of the promises)

On Thu, Feb 25, 2016 at 10:17 AM, Benjamin Gruenbaum 
wrote:

> For what it's worth, bluebird promises detect the error and reject with:
>
> ```
> TypeError: Chaining cycle detected for promise #
> ```
>
> So it's both possible and not a performance issue. For this case, a
> WeakMap is not needed for this case. https://jsfiddle.net/41ez2b6d/ .
>
>
> > We ran into code "in the wild"
>
> Yes, while I've never run into this I've talked to several people who have
> ran into this error - so it's definitely "a thing".
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: non-self referencial cyclical promises?

2016-02-25 Thread Benjamin Gruenbaum
For what it's worth, bluebird promises detect the error and reject with:

```
TypeError: Chaining cycle detected for promise #
```

So it's both possible and not a performance issue. For this case, a WeakMap
is not needed for this case. https://jsfiddle.net/41ez2b6d/ .


> We ran into code "in the wild"

Yes, while I've never run into this I've talked to several people who have
ran into this error - so it's definitely "a thing".
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


non-self referencial cyclical promises?

2016-02-24 Thread Raul-Sebastian Mihăilă
When I first read that part of the spec, my understanding was that the two
promises would cancel each other out by waiting for each other, but without
performing an infinite set of PromiseJobs. The resolving functions created
in step 1 of 25.4.2.2 that are set as reactions for the other promise are
never triggered because the resolve function of the other promise never
triggers the reactions, instead it just adds a set of resolving function
itself for the other promise.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: non-self referencial cyclical promises?

2016-02-24 Thread Dean Tribble
I agree that the standard shoudl require a deterministic error, and I
thought it did. In
https://tc39.github.io/ecma262/#sec-promise-resolve-functions:

6. If SameValue(resolution, promise) is true, then
>   a.Let selfResolutionError be a newly created TypeError object.
>   b.Return RejectPromise(promise, selfResolutionError).


I suspect I assumed to much for "SameValue" here though. There's no
well-defined other semantic answer to a cycle; it essentially always
represents a bug, but could emerge dynamically out of bad code. You must
either catch that as soon as possible or it's extremely difficult to
isolate.

Another approach to efficiently achieve this in the implementation is to
vigorously shorten targets. In this approach, the `bf(a)` would first
shorten `a` so that it's internally pointing at the cell that `bf` will
resolve to (chains are typically short, so keeping chains short is
typically fast). Then the cycle check is simple and O(1). All the work is
in shortening. There are some patterns that can make for interim long
chains but they are straightforward to avoid.

On Wed, Feb 24, 2016 at 12:16 PM, Mark S. Miller  wrote:

>
>
> On Wed, Feb 24, 2016 at 11:54 AM, Bergi  wrote:
>
>> Bradley Meck wrote:
>>
>>> I was doing some recursive data structure work and ended up with a
>>> cyclical
>>> promise that did not use a direct self reference. It can be reduced down
>>> to:
>>>
>>> ```javascript
>>> var af, a = new Promise(f=>af=f);
>>> var bf, b = new Promise(f=>bf=f);
>>>
>>> af(b);bf(a); // the problem
>>>
>>> a.then(_=>_) // some env/libs need this to start checking status
>>> ```
>>>
>>> According to
>>> https://tc39.github.io/ecma262/#sec-promise-resolve-functions
>>> it looks like this should cause a recursive and infinite set of
>>> `EnqueueJob("PromiseJobs",...)`
>>>
>>
>> I fear that's what the standard says, yes. The ES6 spec does too many
>> (and in some cases, unreasonably many) `then` calls on promises anyway to
>> be followed by an efficient promise implementation.
>>
>> [Promises/A+](https://promisesaplus.com/) in contrast says
>>
>> | Implementations are encouraged, but not required, to detect such
>> | recursion and reject promise with an informative TypeError as the
>> | reason.
>>
>
> I think the standard *should* require a deterministic error. E <
> https://github.com/kpreid/e-on-java/blob/master/src/jsrc/org/erights/e/elib/ref/ViciousCycleException.java>,
> Q, and my own Q-like system <
> https://github.com/tvcutsem/es-lab/blob/master/src/ses/makeQ.js#L700> all
> do. Within an engine, this technique should be straightforward to implement
> without slowing down the non-cyclic case.
>
>
>
>
>> Regards,
>>  Bergi
>>
>> ___
>> es-discuss mailing list
>> es-discuss@mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>
>
>
> --
> Cheers,
> --MarkM
>
> ___
> 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: non-self referencial cyclical promises?

2016-02-24 Thread Mark S. Miller
On Wed, Feb 24, 2016 at 11:54 AM, Bergi  wrote:

> Bradley Meck wrote:
>
>> I was doing some recursive data structure work and ended up with a
>> cyclical
>> promise that did not use a direct self reference. It can be reduced down
>> to:
>>
>> ```javascript
>> var af, a = new Promise(f=>af=f);
>> var bf, b = new Promise(f=>bf=f);
>>
>> af(b);bf(a); // the problem
>>
>> a.then(_=>_) // some env/libs need this to start checking status
>> ```
>>
>> According to
>> https://tc39.github.io/ecma262/#sec-promise-resolve-functions
>> it looks like this should cause a recursive and infinite set of
>> `EnqueueJob("PromiseJobs",...)`
>>
>
> I fear that's what the standard says, yes. The ES6 spec does too many (and
> in some cases, unreasonably many) `then` calls on promises anyway to be
> followed by an efficient promise implementation.
>
> [Promises/A+](https://promisesaplus.com/) in contrast says
>
> | Implementations are encouraged, but not required, to detect such
> | recursion and reject promise with an informative TypeError as the
> | reason.
>

I think the standard *should* require a deterministic error. E <
https://github.com/kpreid/e-on-java/blob/master/src/jsrc/org/erights/e/elib/ref/ViciousCycleException.java>,
Q, and my own Q-like system <
https://github.com/tvcutsem/es-lab/blob/master/src/ses/makeQ.js#L700> all
do. Within an engine, this technique should be straightforward to implement
without slowing down the non-cyclic case.




> Regards,
>  Bergi
>
> ___
> es-discuss mailing list
> es-discuss@mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>



-- 
Cheers,
--MarkM
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: non-self referencial cyclical promises?

2016-02-24 Thread Bergi

Bradley Meck wrote:

I was doing some recursive data structure work and ended up with a cyclical
promise that did not use a direct self reference. It can be reduced down to:

```javascript
var af, a = new Promise(f=>af=f);
var bf, b = new Promise(f=>bf=f);

af(b);bf(a); // the problem

a.then(_=>_) // some env/libs need this to start checking status
```

According to https://tc39.github.io/ecma262/#sec-promise-resolve-functions
it looks like this should cause a recursive and infinite set of
`EnqueueJob("PromiseJobs",...)`


I fear that's what the standard says, yes. The ES6 spec does too many 
(and in some cases, unreasonably many) `then` calls on promises anyway 
to be followed by an efficient promise implementation.


[Promises/A+](https://promisesaplus.com/) in contrast says

| Implementations are encouraged, but not required, to detect such
| recursion and reject promise with an informative TypeError as the
| reason.

Regards,
 Bergi
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: non-self referencial cyclical promises?

2016-02-24 Thread Kris Kowal
With Mark’s direction, the v2 branch of Q handles "vicious cycles" through
the WeakMap that maps promises to their underlying handler. Whenever a
promise is resolved with another promise, it walks forward through the
chain of promises that the promise handler "became" through resolution. The
first promise’s initial handler is a "vicious cycle" rejected promise
handler, so if the walk forward through the resolution returns to itself,
it remains resolved to the vicious cycle.

https://github.com/kriskowal/q/blob/v2/q.js#L181-L204

On Wed, Feb 24, 2016 at 11:38 AM Bradley Meck 
wrote:

> I was doing some recursive data structure work and ended up with a
> cyclical promise that did not use a direct self reference. It can be
> reduced down to:
>
> ```javascript
> var af, a = new Promise(f=>af=f);
> var bf, b = new Promise(f=>bf=f);
>
> af(b);bf(a); // the problem
>
> a.then(_=>_) // some env/libs need this to start checking status
> ```
>
> According to https://tc39.github.io/ecma262/#sec-promise-resolve-functions
> it looks like this should cause a recursive and infinite set of
> `EnqueueJob("PromiseJobs",...)`
>
> This code currently does strange things in stable browsers, but doesn't
> seem to always cause infinite loops in the nightly builds of some things. I
> was wondering what the expected behavior is here because I am having
> trouble making sense of things.
> ___
> 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


non-self referencial cyclical promises?

2016-02-24 Thread Bradley Meck
I was doing some recursive data structure work and ended up with a cyclical
promise that did not use a direct self reference. It can be reduced down to:

```javascript
var af, a = new Promise(f=>af=f);
var bf, b = new Promise(f=>bf=f);

af(b);bf(a); // the problem

a.then(_=>_) // some env/libs need this to start checking status
```

According to https://tc39.github.io/ecma262/#sec-promise-resolve-functions
it looks like this should cause a recursive and infinite set of
`EnqueueJob("PromiseJobs",...)`

This code currently does strange things in stable browsers, but doesn't
seem to always cause infinite loops in the nightly builds of some things. I
was wondering what the expected behavior is here because I am having
trouble making sense of things.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Promises as Cancelation Tokens

2016-01-13 Thread Benjamin Gruenbaum
*F# cancellation* - on second thought implicit cancellation through
cancellation like in F# is impractical because of the eagerness of
promises. I don't think it's a valid alternative here. I've discussed this
with Reed Copsey (an F# expert) and he explained the philosophy behind it
to me - it doesn't sound practical for JavaScript promises at all.

*Splitting into abort and ignore semantics - *that sounds like a great
idea, I think that ignore semantics are far more common for the use cases I
run into by the way. I think it might be a good idea to fire this off in a
separate ES-Discuss thread.

*Throwing and implicit cancellation *- I agree with Katelyn, throwing and
ignore cancellation are exclusive. As Bradley said - `return` (as in
generator `.return`) is a better mental model. `finally` blocks are run but
not `catch` blocks. In bluebird 3, cancellation is done with ignore
semantics - and we don't `throw` on cancellation (link again for
comparison: http://bluebirdjs.com/docs/api/cancellation.html ).

*Implicit cancellation being opt in - *I agree too, the nice property is
that cancellation becomes an optimization library authors get to make but
no other code breaks. A library can add support for freeing requests
earlier and you don't have to change your code in order to get the
optimization.

*Socket Lifetime Example - *In bluebird we map that with disposers (ref:
http://bluebirdjs.com/docs/api/promise.using.html ), we have found that in
the last few years although the library gets millions of downloads very few
people actually use `using`. It is an interesting motivating example and I
think we should collect those for any future proposal.

*XHR Example *- I think that ignore semantics can model that. The XHR
saving important changes would simply not be cancellable under implicit
cancellation - trying to cancel it would result in a no-op.

Cheers


On Wed, Jan 13, 2016 at 12:13 AM, Katelyn Gadd  wrote:

> Implicit cancellation doesn't make sense if it involves a throw.
> Furthermore, implicit cancellation would never happen for your example
> - the 'await' clearly depends on the result of the operation, so it is
> in use and it would not make sense for it to be implicitly cancelled.
> For the record, every time I've successfully dealt with implicit
> cancellation, it's opt-in - the library author implementing the
> asynchronous logic decides whether or not it will respond to implicit
> cancellation.
>
> Explicit cancellation ('abort', to use the terminology split Bradley
> advocated above) would potentially introduce a throw there, but that
> should be unsurprising, just as a socket being closed due to an
> ethernet cable getting unplugged would cause a socket operation to
> throw "unexpectedly".
>
>
> There are some subtle distinctions here that APIs tend to get wrong,
> of course. An example that might be informative:
>
> If you look at sockets, various APIs tend to have differences in how
> you deal with lifetime & closing handles. In some cases there are
> subtly different forms operations - for example if you look at Socket
> in the .NET framework, it exposes *three different/overlapping forms
> of lifetime management*, through the Shutdown, Close and Dispose
> methods. If you compare this with Rust's sockets API, the only
> explicit operation it exposes is 'shutdown', and the other two are
> expressed by dropping the value.
>
> For the average .NET user, you can treat all three as equivalent. For
> casual use cases you can just Dispose all IDisposable resources
> (files, sockets, graphics resources...) at the end of a function and
> be ready to go. But behaviorally they are different, and semantically
> they are different. A socket Shutdown followed by a Dispose will flush
> the read/write buffers (which can take time) and allow you to cleanly
> tear everything down, while a standalone Dispose is an instantaneous
> destruction of the socket, potentially breaking a transmission in the
> middle. In practice, this distinction represents that the socket is
> actually a group of related resources - read/write buffers, a network
> connection, etc - that can't simply be treated as a single unit with
> consistent lifetime.
>
> Oh yeah, and there's also the detail that you can shut down the write
> end of a socket but not the read end. :-)
>
> If you map this over to the browser, you can trivially come up with
> equivalent examples. When I issue XHR requests, some of those requests
> are more important than others. For example, an XHR that is saving
> important changes to an email draft should not be aborted if the user
> clicks on a hyperlink to load a new email. However, an XHR that is
> downloading an inline image for an email *can* be safely 

Re: Promises as Cancelation Tokens

2016-01-12 Thread Katelyn Gadd
Implicit cancellation doesn't make sense if it involves a throw.
Furthermore, implicit cancellation would never happen for your example
- the 'await' clearly depends on the result of the operation, so it is
in use and it would not make sense for it to be implicitly cancelled.
For the record, every time I've successfully dealt with implicit
cancellation, it's opt-in - the library author implementing the
asynchronous logic decides whether or not it will respond to implicit
cancellation.

Explicit cancellation ('abort', to use the terminology split Bradley
advocated above) would potentially introduce a throw there, but that
should be unsurprising, just as a socket being closed due to an
ethernet cable getting unplugged would cause a socket operation to
throw "unexpectedly".


There are some subtle distinctions here that APIs tend to get wrong,
of course. An example that might be informative:

If you look at sockets, various APIs tend to have differences in how
you deal with lifetime & closing handles. In some cases there are
subtly different forms operations - for example if you look at Socket
in the .NET framework, it exposes *three different/overlapping forms
of lifetime management*, through the Shutdown, Close and Dispose
methods. If you compare this with Rust's sockets API, the only
explicit operation it exposes is 'shutdown', and the other two are
expressed by dropping the value.

For the average .NET user, you can treat all three as equivalent. For
casual use cases you can just Dispose all IDisposable resources
(files, sockets, graphics resources...) at the end of a function and
be ready to go. But behaviorally they are different, and semantically
they are different. A socket Shutdown followed by a Dispose will flush
the read/write buffers (which can take time) and allow you to cleanly
tear everything down, while a standalone Dispose is an instantaneous
destruction of the socket, potentially breaking a transmission in the
middle. In practice, this distinction represents that the socket is
actually a group of related resources - read/write buffers, a network
connection, etc - that can't simply be treated as a single unit with
consistent lifetime.

Oh yeah, and there's also the detail that you can shut down the write
end of a socket but not the read end. :-)

If you map this over to the browser, you can trivially come up with
equivalent examples. When I issue XHR requests, some of those requests
are more important than others. For example, an XHR that is saving
important changes to an email draft should not be aborted if the user
clicks on a hyperlink to load a new email. However, an XHR that is
downloading an inline image for an email *can* be safely aborted at a
moment's notice. You can think of this as equivalent to
Shutdown/Dispose - you would want to Shutdown the draft save
operation, flushing everything out, before closing the socket, and
that takes time. In comparison, the image load is implicitly cancelled
as soon as the image content is no longer needed, and that can
terminate the underlying request if appropriate.


On 11 January 2016 at 19:59, Kevin Smith  wrote:
>> I think F#'s cancellation approach is also worth mentioning in the
>> discussion of alternatives as it has implicit but token-based automatically
>> propagating cancellation.
>
>
> If you have any good links to reference materials on F#'s cancellation
> architecture, feel free to include them for future reference.  I was unable
> to find anything that clearly explained how implicit cancellation tokens are
> discovered by child tasks, for instance.
>
> I find implicit cancellation to be somewhat sketchy.  For async functions,
> it would mean that any await expression could potentially throw a
> CancelError:
>
> async function f() {
>   let a = await 1; // This could throw?  What?
> }
>
> And there are certainly going to be scenarios where you *don't* want to
> cancel a subtask.  It seems to me that cancellation semantics are best left
> to the async operation itself, rather than assuming "crash-and-burn".
>
>
> ___
> 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: Promises as Cancelation Tokens

2016-01-12 Thread Bradley Meck
>
> For async functions, it would mean that any await expression could
> potentially throw a CancelError


Cancellation does not necessarily need to use `throw`, `return` is often
more apt. I find.

I would also recommend splitting the idea of cancellation into: abort
semantics, and ignorance semantics. Trying to use one term for both
separately is getting confusing.

My usage of cancellation is often being able to undo side-effects which can
happily be done using `finally`.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Promises as Cancelation Tokens

2016-01-11 Thread Kevin Smith
>
> I think F#'s cancellation approach is also worth mentioning in the
> discussion of alternatives as it has implicit but token-based automatically
> propagating cancellation.
>

If you have any good links to reference materials on F#'s cancellation
architecture, feel free to include them for future reference.  I was unable
to find anything that clearly explained how implicit cancellation tokens
are discovered by child tasks, for instance.

I find implicit cancellation to be somewhat sketchy.  For async functions,
it would mean that any await expression could potentially throw a
CancelError:

async function f() {
  let a = await 1; // This could throw?  What?
}

And there are certainly going to be scenarios where you *don't* want to
cancel a subtask.  It seems to me that cancellation semantics are best left
to the async operation itself, rather than assuming "crash-and-burn".
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Promises as Cancelation Tokens

2016-01-11 Thread Benjamin Gruenbaum
> Another cancellation scenario is when the consumer of an asynchronous
task no longer
> needs the result of an operation. In this case, they will only have
access to the Promise
> unless the cancellation token is routed to them through some other path.

For what it's worth - this is exactly how promise cancellation is modeled
in bluebird 3 and we have found it very nice.

I think the distinction between cancellation because of disinterest and
cancellation because we actively want to cancel the operation is very
important - props for nailing it.

That said - I think most scenarios that work with tokens work without them
and vice versa.

I think F#'s cancellation approach is also worth mentioning in the
discussion of alternatives as it has implicit but token-based automatically
propagating cancellation.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Promises as Cancelation Tokens

2016-01-11 Thread Katelyn Gadd
One key thing to recognize is that there are different reasons to
cancel an operation and as a result, different approaches to
cancellation. .NET cancellation tokens address one scenario (and do it
fairly well), where the objective is for specific operations to expose
cancellation and allow the caller to set up a way to cancel the
operation once it is in progress. This requires co-operation on both
sides but is very easy to debug and reason about.

However, this does not address all cancellation scenarios.

Another cancellation scenario is when the *consumer* of an
asynchronous task no longer needs the result of an operation. In this
case, they will only have access to the Promise unless the
cancellation token is routed to them through some other path. This
becomes especially unwieldy if you are dealing with a graph of
asynchronous operations, where you want this 'no longer needed'
property to propagate through all of the promises. This is somewhat
equivalent to how you want a garbage collector to collect a whole tree
of objects once they are no longer reachable. In JS (and in my
opinion, basically all language environments) you want this to be
explicit even if the GC is able to lazily flag the result of a promise
as no longer needed. In the 'result no longer needed' scenario there
are also cases where you do not want to cancel the operation even if
it is not needed anymore.

A third form of cancellation is already addressed by Promise
implementations - error handling. In this case, an error occurs and
the whole asynchronous process (usually) needs to be aborted and
unwound so that the error can be responded to. In this scenario
cancellation can occur at any time and in some cases it is not
possible for the application to continue correctly under these
circumstances. You could use exceptions to implement the other forms
of cancellation, but it's pretty unwieldy - and injecting exceptions
into code that doesn't expect that is a generally bad policy. .NET
used to allow injecting exceptions into other threads but has since
deprecated it because of all the nasty corner cases it introduces.

In my opinion cancellation tokens are a great model that does not
require any browser vendor/VM implementer support, but it can be
beneficial for implementations of specific operations (i.e. XHR) to
provide some sort of cancellation mechanism. Essentially, the XHR
object acts as the cancellation token and you call a method on it to
cancel. In most cases you can implement that in user space.

'Result no longer needed' requires some amount of support at the
language/base framework level, so that it is possible to flag this
state on any given Promise and it is possible for all Promise
consumers to appropriately propagate this state through graphs of
asynchronous dependencies. For example, cancelling a HTML pageload
should flag any dependent image/script loads as 'no longer needed',
but not necessarily *abort* them (aborting might kill the keepalive
connection, and allowing the request to complete might helpfully prime
the cache with those resources).

-kg

On 5 January 2016 at 19:58, Kevin Smith  wrote:
> Thanks for posting this.  Great stuff!
>
>>
>> On a page that loads 100 images four at a time, you would want 4 cleanup
>> actions registered, not 100.
>
>
> And in order to keep it to 4 you need a way to unregister the action when
> you complete the operation, which the promise API doesn't give you.  I see.
>
> Conceptually, you could of course set some "complete" flag when you finish
> the operation and then have the cleanup action early-exit if that flag is
> set, but that would be unwieldy.  And it wouldn't stop the unbounded growth
> of the promise's handler list.
>
> Interesting!
>
>
> ___
> 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: Promises as Cancelation Tokens

2016-01-05 Thread Kevin Smith
Thanks for posting this.  Great stuff!


> On a page that loads 100 images four at a time, you would want 4 cleanup
> actions registered, not 100.
>

And in order to keep it to 4 you need a way to unregister the action when
you complete the operation, which the promise API doesn't give you.  I see.

Conceptually, you could of course set some "complete" flag when you finish
the operation and then have the cleanup action early-exit if that flag is
set, but that would be unwieldy.  And it wouldn't stop the unbounded growth
of the promise's handler list.

Interesting!
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Promises as Cancelation Tokens

2016-01-05 Thread Kevin Smith
Thanks Ron!  Comments inline...

> ·   Once a callback has been registered for asynchronous notification
> of a cancellation signal, it can later be unregistered.
>
Yes, I see how this could be helpful.

> ·   Asynchronous notifications are queued and handled at a higher
> priority than Promise continuations.
>
> ·   The reason for cancellation can be explicitly supplied. If not
> supplied, the reason would be a generic “The operation was canceled” error.
>
What's the benefit of allowing a user-supplied error?  (I assume that by
convention the reason should be an error type.)  I don't see that feature
in .NET.

> Since “source.cancel()” is executed synchronously, one would expect that
> `p` would be rejected. If the notification were merely added to the same
> micro-task queue as Promise “then” tasks, `p` would be resolved first.
>
I agree that your example, as written, is counter-intuitive.  However, is
it still counter-intuitive if I rewrite it like this?

// Suppose I have "cancelToken" and "cancel"
let p = new Promise((resolve, reject) => {
  Promise.resolve(1).then(resolve);
  cancelToken.promise.then(reject);
  cancel();
});

Written like this, it seems to me that the ordering is as expected.  Are
there use cases that require a higher priority, beyond user expectation
based on the API?

In .NET, cancellation notifications are executed synchronously, however
> this conflicts with the intent to ensure an asynchronous API is
> consistently asynchronous.
>
Right.  The trouble I have with introducing an ad-hoc callback API for
cancel tokens centers mostly around the handling and propagation of
errors.  In .NET, exceptions which occur inside of callbacks are propagated
synchronously to the caller via an AggregateException error collection.
But if the callbacks are truly executed asynchronously, where do the errors
go?  Do they propagate out to the host, like HTML event handlers?  It would
be unfortunate if no mechanism was provided by ECMAScript itself to handle
such errors.

Since we already have a well-defined and well-understood way to propagate
errors using promises, I would prefer to have the async registration
capability modeled as a promise, if possible.  There is that "unregister"
issue, though...
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Promises as Cancelation Tokens

2016-01-04 Thread Dean Tribble
>From experience, I'm very much in favor of the cancellation token.  Though
promises provide a good inspiration for cancellation, they don't quite fit
the problem directly.

The approach has been explored, though the details are not published. I
implemented cancellation for the Midori system. Midori was an incubation
project to build a new OS, applications, etc. in a safe language (a C#
variant) using lightweight processes communicating via promises (easily 2M+
lines of C#). Among other things, it strongly influenced the C# async
support. See http://joeduffyblog.com/2015/11/19/asynchronous-everything/
for more info. After looking at various options, the approach developed for
.Net covered all the requirements we had and could be adapted surprisingly
well to the async world of promises and Midori. There were some important
differences though.

In a concurrent, async, or distributed system, cancellation is
*necessarily *asynchronous: there's fundamentally a race between a
computation "expanding" (spawning more work) and cancellation running it
down. But as you note, a cancellation system must support the ability to
*synchronously *and cheaply test whether a computation is being cancelled.
That allows one for example to write a loop over thousands of records that
will abort quickly when cancelled without scheduling activity for the
remaining records. (Because of the inherent race in cancellation, I named
that "isCancelling" rather than "isCancelled" to be a small reminder that
computation elsewhere might not yet have heard that it should stop.)

In async cancellation, the promise "then" seems like it could support the
asycn "cleanup" action on cancellation. However there are a lot of
cancellation use cases in which the appropriate cleanup action changes as a
computation proceeds. For those, using "then" is not adequate. For example,
a browser would have a cancellation token associated with a page load. Thus
the same token is used during parsing, retrieving secondary images, layout,
etc. If the user hits "stop", the token is cancelled, and so all the
various heterogeneous page rendering activities are cancelled. But the
cleanup action to "close the socket that you are retrieving an image over"
becomes expensive deadweight once the image has been retrieved. On a page
that loads 100 images four at a time, you would want 4 cleanup actions
registered, not 100.

For that and other reasons, we found it much clearer to give
cancellationToken it's own type. That also allows convenient patterns to be
directly supported, such as:

async function f(cancel) {
  await cheapOperation(cancel);
  cancel.*throwIfCancelling*(); // throws if the token is cancelling
  await expensiveOperation(cancel);
}

Note that the above would more likely have been written simply:

async function f(cancel) {
  await cheapOperation(cancel);
  await expensiveOperation(cancel);
}

The reason is that if the cheapOperation was aborted, the first await would
throw (assuming cheapOperation terminates abruptly or returns a broken
promise). If it got past cheapOperation, we already know that
expensiveOperation is going to be smart enough to cancel, so why clutter
our world with redundant aborts?  e.g.,

async function expensiveOperation(cancel) {
  while (hasFramesToRender() && !cancel.isCancelling()) {
  await renderFrame(this.nextFrame(), cancel);
  }
}

Thus, using cancellation tokens becomes simpler as cancellation becomes
more pervasive in the libraries. Typically, if an operation takes a
cancellation token as an argument, then you don't need to bother protecting
it from cancellation. As a result, explicit cancellation handling tends to
only be needed in lower level library implementation, and client code
passes their available token to either operations or to the creation of
objects (e.g., pass in your token when you open a file rather than on every
file operation).



On Mon, Jan 4, 2016 at 7:46 AM, Kevin Smith  wrote:

> I'm interested in exploring the idea of using an approach similar to
> .NET's cancelation tokens in JS for async task cancelation.  Since the
> cancelation "flag" is effectively an eventual value, it seems like promises
> are well-suited to modeling the token.  Using a promise for a cancelation
> token would have the added benefit that the eventual result of any
> arbitrary async operation could be used as a cancelation token.
>
> First, has this idea been fully explored somewhere already?  We've
> discussed this idea on es-discuss in the past, but I don't remember any
> in-depth analysis.
>
> Second, it occurs to me that the current promise API isn't quite ideal for
> cancelation tokens, since we don't have synchronous inspection
> capabilities.  For example, suppose t

RE: Promises as Cancelation Tokens

2016-01-04 Thread Ron Buckton

This gist<https://gist.github.com/rbuckton/b69be537e41feec7fea7> contains the 
TypeScript declarations for the version of CancellationToken I’ve been using 
for a number of small projects. The basic API shape is:

```ts
class CancellationTokenSource {
  constructor(linkedTokens?: CancellationToken[]);
  token: CancellationToken;
  cancel(reason?: any): void;
  close(): void;
}
class CancellationToken {
  static none: CancellationToken;
  canBeCanceled: boolean;
  canceled: boolean;
  reason: any;
  throwIfCanceled(reason?: any): void;
  register(callback: (reason?: any) => void): CancellationTokenRegistration;
}
interface CancellationTokenRegistration {
  unregister(): void;
}
```

The approach I use has the following considerations:


•   The responsibility for cancellation is split between two types:

o   CancellationTokenSource – This type is responsible for propagating a 
cancellation signal and linking multiple tokens together (useful to cancel a 
graph of async operations, such as cancelling all pending fetch request).

o   CancellationToken – A read-only sink for a cancellation signal. 
Asynchronous operations can either synchronously observe whether the 
cancellation signal has been set, or register an callback for asynchronous 
notification of a cancellation signal.

•   Once a callback has been registered for asynchronous notification of a 
cancellation signal, it can later be unregistered.

•   Asynchronous notifications are queued and handled at a higher priority 
than Promise continuations.

•   The reason for cancellation can be explicitly supplied. If not 
supplied, the reason would be a generic “The operation was canceled” error.

Splitting a cancellation signal across two classes has several benefits. One 
benefit is that it allows the producer of a cancellation signal to limit access 
to the ability to initiate that signal. This is important if you wish to have a 
single shared cancellation source for multiple concurrent asynchronous 
operations, but need to hand off a cancellation token to a third party without 
worrying that the third party code would unintentionally cancel operations that 
it does not itself own. Another benefit is the ability to create more complex 
cancellation graphs through linking multiple cancellation tokens.

I agree with Domenic that it is necessary to be able to synchronously observe 
the canceled state of a cancellation token, and that it is also necessary to be 
able to observe a cancellation signal asynchronously. However, I have found 
that the asynchronous notification needs to be triggered at a higher priority 
than Promise “then” tasks. Consider the following, albeit contrived, example:

```js
let source = new CancellationTokenSource();
let p = new Promise((resolve, reject) => {
  Promise.resolve(1).then(resolve);
  source.token.register(reject);
  source.cancel();
});
```

Since “source.cancel()” is executed synchronously, one would expect that `p` 
would be rejected. If the notification were merely added to the same micro-task 
queue as Promise “then” tasks, `p` would be resolved first. By making the 
micro-task queue into a priority queue, we can allow cancellation notifications 
to be processed at a higher priority while still keeping the API itself 
asynchronous. In .NET, cancellation notifications are executed synchronously, 
however this conflicts with the intent to ensure an asynchronous API is 
consistently asynchronous.

This approach also allows cancellation tokens to be more general-purpose. By 
not directly tying cancellation into Promises, they can be used with other 
future asynchronous primitives such as Observables, async generators, etc.

Ron

From: Kevin Smith<mailto:zenpars...@gmail.com>
Sent: Monday, January 4, 2016 11:44 AM
To: Tab Atkins Jr.<mailto:jackalm...@gmail.com>; Domenic 
Denicola<mailto:d...@domenic.me>
Cc: es-discuss<mailto:es-discuss@mozilla.org>
Subject: Re: Promises as Cancelation Tokens

The best approach in cases like this is to avoid the word altogether.
The fact that there's confusion at all means people will mess it up
and get annoyed, even if there's a "winner" in overall usage.

Hmmm...  Maybe

class CancelToken {
  constructor(init);
  get cancelRequested() : bool;
  whenCancelRequested(callback) : void;
}

Or more/overly tersely:

class CancelToken {
  constructor(init);
  get requested() : bool;
  whenRequested(callback) : void;
}




___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Promises as Cancelation Tokens

2016-01-04 Thread Benjamin Gruenbaum
> We could use a promise subclass as the cancellation token, but then
tokens (and their constructor) would inherit things that really don't make
sense, like "CancelToken.resolve" and "CancelToken.prototype.catch".

Generally I dislike inheritance. I was merely saying it's an option. I
favor composition here as well.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Promises as Cancelation Tokens

2016-01-04 Thread Kevin Smith
>
> I think using promises as tokens would be problematic. It would have
> several issues:
>

Agreed with all of those.

It's also important to keep in mind that promises can be subclassed so it's
> fine to add properties to them if used for a specific purpose like
> cancellation.
>

We could use a promise subclass as the cancellation token, but then tokens
(and their constructor) would inherit things that really don't make sense,
like "CancelToken.resolve" and "CancelToken.prototype.catch".

On the other hand, it doesn't really make sense to create a new callback
API (`whenCancelled`), when we already have the necessary callback
semantics with promises.  Perhaps we can expose a promise on the token
instead:

class CancelToken {
get requested() : bool;
get promise() : Promise;
throwIfRequested() : void;
}

// Registering a callback
token.promise.then(_=> doSomething());

// Doing other things with the promise
Promise.race(token.promise, someOtherPromise);
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Promises as Cancelation Tokens

2016-01-04 Thread Kevin Smith
> throw() { throw new CancelError() }
>

This should be `throwIfRequested` I think, e.g.

throwIfRequested() {
  if (this._requested)
throw new CancelError();
  }
}


> What would be the recommended way of keeping the internal state
> private? With a WeakMap?
>

Spec-defined objects can have "internal slots" (essentially private
fields), which can be simulated with WeakMaps.  Although a polyfill would
most likely just use underscored names.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Promises as Cancelation Tokens

2016-01-04 Thread /#!/JoePea
Cool, yeah, the reveal pattern would indeed be a good way to guard
against unwanted/unexpected cancels.

```js
class Cancel {
constructor(executor) {
this._requested = false
executor(() => this._requested = true)
}
get requested() {return this._requested}
throw() { throw new CancelError() }
}

let cancel = new Cancel(function(cancel) {
cancelButton.onclick = cancel
})
```

What would be the recommended way of keeping the internal state
private? With a WeakMap?

On Mon, Jan 4, 2016 at 1:01 PM, Kevin Smith  wrote:
>> Since checking `promise.state` is synchronous, we may as well just
>> write a synchronous Cancel class instead:
>
>
> Right - see upthread.  You do need some kind of callback method, though,
> like `whenCancelled(callback)`.
>
>>
>> class Cancel {
>> constructor() { this.requested = false }
>> request() { this.requested = true }
>> throw() { throw new CancelError() }
>> }
>
>
> We need to separate the capability to "read" the cancellation request from
> the ability to request the cancellation.  That's why in .NET you have
> CancellationTokenSource and CancellationToken.  But for JS, we should
> probably use the revealing constructor pattern instead (discussed upthread):
>
> let token = new CancelToken(cancel => { ... });
>
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Promises as Cancelation Tokens

2016-01-04 Thread Kevin Smith
>
> Since checking `promise.state` is synchronous, we may as well just
> write a synchronous Cancel class instead:
>

Right - see upthread.  You do need some kind of callback method, though,
like `whenCancelled(callback)`.


> class Cancel {
> constructor() { this.requested = false }
> request() { this.requested = true }
> throw() { throw new CancelError() }
> }
>

We need to separate the capability to "read" the cancellation request from
the ability to request the cancellation.  That's why in .NET you have
CancellationTokenSource and CancellationToken.  But for JS, we should
probably use the revealing constructor pattern instead (discussed upthread):

let token = new CancelToken(cancel => { ... });
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Promises as Cancelation Tokens

2016-01-04 Thread Benjamin Gruenbaum
> Cool, I'm aware that cancellable promises have been explored in depth.
I'd prefer to keep this thread focused on cancellation tokens though, and
avoid comparisons.

Cool, re-reading the discussion you asked for this in the first message - I
apologize for missing it.

I think using promises as tokens would be problematic. It would have
several issues:

 - You'd want to be able to  `cancel` things like Promise.all and
`Promise.race` - with a separate type you can use "the last argument", with
a promise you would not be able.
 - The names would get confusing for the users. Like Domenic said -
`whenCancelled` sounds a lot clearer. Sort of like the function vs. object
discussion on es-observable.
 - You get some weird scenarios like cancelling a cancellation.
 - You'd probably need to add properties anyway so that tokens can be
aggregated.

I do definitely see the use for `whenCancelled` and have used its
equivalent myself in C#.


It's also important to keep in mind that promises can be subclassed so it's
fine to add properties to them if used for a specific purpose like
cancellation.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Promises as Cancelation Tokens

2016-01-04 Thread /#!/JoePea
Since checking `promise.state` is synchronous, we may as well just
write a synchronous Cancel class instead:

```js
class CancelError extends Error { /* ... */ }

class Cancel {
constructor() { this.requested = false }
request() { this.requested = true }
throw() { throw new CancelError() }
}

async function f(cancel) {
await cheapOperation(cancel) // some other function might call
cancel.request() while we await here.
if (!cancel.requested)
await expensiveOperation(cancel)
}

let cancel = new Cancel
cancelButton.onclick = () => cancel.request()
f(cancel)
```

Wouldn't this be better than using a Promise if we are relying on a
synchronous check anyways?

On Mon, Jan 4, 2016 at 12:30 PM, Kevin Smith  wrote:
>> We have pretty sound cancellation semantics in bluebird 3.
>
>
> Cool, I'm aware that cancellable promises have been explored in depth.  I'd
> prefer to keep this thread focused on cancellation tokens though, and avoid
> comparisons.
>
>
> ___
> 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: Promises as Cancelation Tokens

2016-01-04 Thread Kevin Smith
>
> We have pretty sound cancellation semantics in bluebird 3.
>

Cool, I'm aware that cancellable promises have been explored in depth.  I'd
prefer to keep this thread focused on cancellation tokens though, and avoid
comparisons.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Promises as Cancelation Tokens

2016-01-04 Thread Benjamin Gruenbaum
We have pretty sound cancellation semantics in bluebird 3. 

http://bluebirdjs.com/docs/api/cancellation.html

Handles multiple subscribers soundly. Solves the common use cases pretty well - 
has absolutely zero magic and pretty simple semantics. They work with .all and 
.race too. 

We have had a lot of positive feedback regarding the change and it works well 
(at least in my code) with async/await and other newer proposals.

Biggest downside is that it hasn't been used for very long yet in production 
( On 4 Jan 2016, at 19:55, Tab Atkins Jr.  wrote:
> 
>> On Mon, Jan 4, 2016 at 9:01 AM, Domenic Denicola  wrote:
>> From: Kevin Smith [mailto:zenpars...@gmail.com]
>> 
>>> And what's the deal, is it canceled or cancelled?  : )
>> 
>> This is kind of the worst. Previous discussion at 
>> https://github.com/promises-aplus/cancellation-spec/issues/4.
>> 
>> Data seems to favor cancelled:
>> 
>> - 
>> https://books.google.com/ngrams/graph?content=canceled%2Ccancelled&year_start=1800&year_end=2020&corpus=15&smoothing=3&share=&direct_url=t1%3B%2Ccanceled%3B%2Cc0%3B.t1%3B%2Ccancelled%3B%2Cc0
>> - http://www.google.com/trends/explore#q=cancelled%2C%20canceled&cmpt=q
>> - http://www.googlefight.com/canceled-vs-cancelled.php
> 
> The best approach in cases like this is to avoid the word altogether.
> The fact that there's confusion at all means people will mess it up
> and get annoyed, even if there's a "winner" in overall usage.
> 
> On Mon, Jan 4, 2016 at 9:36 AM, Kevin Smith  wrote:
>>> I am also unsure when .whenCanceled is necessary
>> 
>> Maybe in the case where you have a promise-returning function and you want
>> to reject the returned promise upon cancellation.
>> 
>>function delayWithCancel(ms, cancelToken) {
>>  return new Promise((resolve, reject) => {
>>setTimeout(resolve, ms);
>>cancelToken.whenCancelled(reject);
>>  });
>>}
> 
> Yes, forcing people to poll an attribute of a Promise-like thing is
> kinda ridic. ^_^
> 
> ~TJ
> 
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Promises as Cancelation Tokens

2016-01-04 Thread Kevin Smith
>
> The best approach in cases like this is to avoid the word altogether.
> The fact that there's confusion at all means people will mess it up
> and get annoyed, even if there's a "winner" in overall usage.
>

Hmmm...  Maybe

class CancelToken {
  constructor(init);
  get cancelRequested() : bool;
  whenCancelRequested(callback) : void;
}

Or more/overly tersely:

class CancelToken {
  constructor(init);
  get requested() : bool;
  whenRequested(callback) : void;
}
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


  1   2   3   4   >