28

Given an array of promises, what's the idiomatic way to get the results in ES7?

Here's what I want to do:

async function getImports() {
  let imports = [System.import('./package1.js'), System.import('./package2.js')];
  let promises = await* imports;
  let results = [];
  await promises.forEach(val => val.then(data => results.push(data))); //seems hacky
  console.log(results); // array of 2 resolved imports
}

The result is correct, but I'm still doing a forEach and a then to turn the resolved promises into results. This just doesn't seem right to me. Is there a cleaner way?

Matt K
  • 4,314
  • 3
  • 19
  • 33
  • Doesn't `promises` already contain the resolved values? At least that's what `let result = await* [Promise.resolve(1), Promise.resolve(2)];` does for me? – m90 Dec 20 '15 at 16:01
  • Yep, each entry in `promises` contains a `[[PromiseValue]]`, but I don't know how to access them without the `forEach` and `then` – Matt K Dec 20 '15 at 16:07
  • That's interesting. I just tried the above being transpiled by babel and it gave me the correct values. What do you use for transpiling? – m90 Dec 20 '15 at 16:09
  • 1
    im using babel 6. You're saying that `promises` returns the results & not promises? – Matt K Dec 20 '15 at 16:10
  • The whole point of `async/await` is to not use promises manually anymore. It's hidden behind async functions and awaiting async functions. – Shanoor Dec 20 '15 at 16:13
  • I ran https://gist.github.com/m90/160f675da4d2abbf9685 in the Babel Repl: https://babeljs.io/repl - this is using Babel 5 though, so maybe something has changed here. – m90 Dec 20 '15 at 16:14
  • Thanks for the gist, so it looks like the return value is `[1,2]` but the `console.log` returns a promise still – Matt K Dec 20 '15 at 16:18
  • I also tried and it [logs `[1, 2]`](https://babeljs.io/repl/#?experimental=false&evaluate=true&loose=false&spec=false&code=async%20function%20getResult()%20%7B%0D%0A%20%20let%20result%20%3D%20await*%20%5BPromise.resolve(1)%2C%20Promise.resolve(2)%5D%3B%0D%0A%20%20console.log(result)%3B%0D%0A%7D%0D%0A%0D%0AgetResult()%3B%0D%0A) – Shanoor Dec 20 '15 at 16:20
  • hmmm, yup you're right it does log the result...wonder if its babel 6 then... – Matt K Dec 20 '15 at 16:21
  • yep, definitely babel 6... – Matt K Dec 20 '15 at 16:22
  • Created issue at https://phabricator.babeljs.io/T6866. Thanks for the sanity check! – Matt K Dec 20 '15 at 16:28
  • I'm trying to use babeljs to compile a simple js file and it's like trying to do voodoo magic: 'async function' is an unexpected token... – Shanoor Dec 20 '15 at 16:50

3 Answers3

43

As mentioned in the issue you filed, the core issue is that await* is no longer a thing and has been removed. Unfortunately, it was not properly throwing a syntax error in Babel 6 and was essentially being treated like a normal await.

You'll need to explicitly

 let [p1, p2] = await Promise.all([
          System.import('./package1.js'), System.import('./package2.js')]);
Alexis Wilke
  • 15,168
  • 8
  • 60
  • 116
loganfsmyth
  • 135,356
  • 25
  • 296
  • 231
  • oh man, sorry to hear it won't be moving forward, but thank you for letting me know! If you have it handy, could you point me to a link on esdiscuss or where ever it was rejected? (this particular thing is hard to search for since no engine indexes `await*`) – Matt K Dec 20 '15 at 18:41
  • 2
    The spec is always the best place to look. The proposed spec syntax is in https://github.com/tc39/ecmascript-asyncawait/blob/master/spec/syntax.html and only defines `await UnaryExpression`. – loganfsmyth Dec 20 '15 at 19:08
  • You might want to take a look at Promise.each method from bluebird to make this code more expressive http://bluebirdjs.com/docs/api/promise.each.html There are still good reasons to use helper libs like Bluebird even with ES7 async await – Filip Sobczak Mar 02 '18 at 12:29
1

I cannot believe it actually works, forEach does return undefined which you cannot await. If you need a loop, use map to get an array of (promised) results.

In your case, you seem to be looking for a simple

async function getImports() {
  let promises = [System.import('./package1.js'), System.import('./package2.js')];
  let results = await Promise.all(promises)
  console.log(results);
}
Bergi
  • 513,640
  • 108
  • 821
  • 1,164
0

One way to do it this ....

async function abc() {
    let p1 = getReviews();
    let p2 = getMenu();
    let [reviews, menu] = await results(p1, p2);
}

function results(...rest) {
    return Promise.all(rest).catch(err => console.log(err));
}
Muhammad Umer
  • 14,722
  • 14
  • 69
  • 139