Skip to content
This repository has been archived by the owner on Feb 2, 2023. It is now read-only.

await* and parallelism is not ideal #25

Closed
davidbau opened this issue Sep 25, 2014 · 11 comments
Closed

await* and parallelism is not ideal #25

davidbau opened this issue Sep 25, 2014 · 11 comments

Comments

@davidbau
Copy link

The proposed await* syntax is not ideal for parallelism. When managing parallel tasks, it is typical to have a set of dissimilar tasks, each launched and finished in a different way. Instead of reducing boilerplate, an idiom where each result needs to be packed and unpacked into an array would increase ceremony

Can we do something that is closer to what is achieved by Iced CoffeeScript? There they have a keyword which introduces a block, within which you should not expect to be able to use the result. Their syntax is something like this:

await
  $.get myurl1, defer result1
  douserinput defer result2
  for j in [0...10]
    $.get myurlarray[j], defer resultarray[j]
# within the wait block, all the requests are launched in parallel...
# then the await block ends, which pauses the program, then after that we have results
answer = result1+ result2 + sum(resultarray)

The main advantage here is clarity: the variable name for the result is directly next to the operation that computes it.

Rather than an array-based await* I think it would be much better to try to mimic Iced's simplicity:

await* {
  result1 = await urlget(url1)
  result2 = await douserinput()
  for (var j = 0; j < 10; ++j) {
    resultarray[j] = await urlget(urlarray[j])
  }
}

Would something like that be possible?

@bterlson
Copy link
Member

It doesn't seem too bad to use something like:

let result1 = urlget(url1);
let result2 = douserinput();
for (var j = 0; j < 10; ++j) {
    resultarray[j] = urlget(urlarray[j]);
}

[result1, result2, ... resultarray] = await Promise.all([result1, result2, ... resultarray]);

@davidbau
Copy link
Author

No, it's not terrible, but it tastes similar, to me, to the ugliness that require.js introduced when they created the "AMD" pattern

define(["package1", "package2", "package3", "package4"], function(package1, package2, package3, package4) {...});

(If you have used that pattern, you will have run into the problem of getting packages mismatched - it's not only ugly but it's error-prone.)

The question is, can we create a syntax that doesn't require listing out parallel arrays?

@bterlson
Copy link
Member

I hear you, I actually named each var three times! In some cases something like this could be acceptable.

let [result1, result2, ... resultarray] = await Promise.all([
    urlget(url1),
    douserinput(),
    urlarray.map(url => urlget(url))
]);

@davidbau
Copy link
Author

Yes, it's the parallel arrays which I'd advocate we try to avoid, since that's inviting bugs (just like the AMD define convention does). Here's something simpler and closer. A syntactic sugar similar to the optional initializers on variable declarations could avoid the issue I am worried about:

await* result1 = urlget(url1),
       result2 = douserinput(),
       resultarray = urlarray.map(url => urlget(url));

@zenparsing
Copy link
Member

I think @bterlson 's solution is a pretty good (and good enough) for this use case.

@matAtWork
Copy link

I have a similar issue over in #29 - whether and how it is desirable to provide a language construct to specify parallelism. My proposal is to be able to precede a loop with the async keyword.

@MatAtBread
Copy link

In nodent, the library function akin to Promise.all (nodent.map) accepts an object as it's argument, as well as an array, giving results like:

var r = await nodent.map({
  URL:getUrl("home"),
  input:doUserInput(elem)
}) ;

redirect(r.URL+"?"+r.input);

This has the advantage of keeping the operation and name in close proximity, making the intent easier to spot, is fully ES5 friendly with respect to the await expression and response, allows for nested parallel persons, and in any case is a runtime implementation and so the programmer can alias the function. I'm not sure there is any real value in creating new syntax to cover this case.

The source at https://github.com/MatAtBread/nodent/blob/master/covers/map.js also allows for an array, object to counter to be mapped by an asynchronous function as a second parameter, but this is simply for convenience and not directly related to the use case in question here

@davidbau
Copy link
Author

That's nice, and that would solve the problem that concerns me.
Promise.all doesn't work that way?

On Tue, Mar 24, 2015 at 2:38 PM, Matt notifications@github.com wrote:

In nodent, the library function akin to Promise.all (nodent.map) accepts
an object as it's argument, as well as an array, giving results like:

var r = await nodent.map({
URL:getUrl("home"),
input:doUserInput(elem)
}) ;

redirect(r.URL+"?"+r.input);

This has the advantage of keeping the operation and name in close
proximity, making the intent easier to spot, is fully ES5 friendly with
respect to the await expression and response, allows for nested parallel
persons, and in any case is a runtime implementation and so the programmer
can alias the function. I'm not sure there is any real value in creating
new syntax to cover this case.

The source at
https://github.com/MatAtBread/nodent/blob/master/covers/map.js also
allows for an array, object to counter to be mapped by an asynchronous
function as a second parameter, but this is simply for convenience and not
directly related to the use case in question here


Reply to this email directly or view it on GitHub
#25 (comment)
.

@lukehoban
Copy link
Collaborator

I think it is worth suggesting that change to Promise.all behavior to TC39 as part of the Promise API. It would be a nice addition that would help here.

I don't think there is anything that needs to change in the async/await proposal related to this thread at this point.

@MatAtBread
Copy link

If someone has a mechanism for submitting this to the correct TC39 group, please feel free to do so (I don't)

@getify
Copy link

getify commented Apr 9, 2015

@MatAtBread you can join the https://mail.mozilla.org/listinfo/es-discuss discussion list, which is how non-TC39'rs submit suggestions/discussions for TC39 to consider.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants