1

I want to sort ids which should return ["b", "a"] in a contrived example point is read below is imposed to be async in real code. I tried this but can't make prevent it to wait for comparison to finish whereas I wait with then :

  async function test(a, b) {
    return await (async (a, b) => {
      let retval;
      let text_a = await read("a");
      let text_b = await read("b");
      retval = (text_a.length - text_b.length);
      return retval;
    })(a, b);
  }

  let ids = ["a", "b"]

  ids = ids.sort(
    function f(a, b) {
      let retval = test(a, b).then(result => result);
      return retval;
    }
  );
  console.log(ids)

  async function read(p) {
    if(p == "a") {
      return "aaaaaaaaaaaaaaaaa";
    }
    if (p == "b") {
      return "bbbbbbbb";
    }
  }
user310291
  • 36,946
  • 82
  • 271
  • 487
  • 3
    You will have to do something like `(await Promise.all(ids.map(`…`))).sort(`…`)`. If you need the original values of the array, map to an object that contains the original value and the awaited `read` result, then [sort by property](/q/1129216/4642212). The `sort` callback cannot be async, because a Promise is not one of the expected return values. – Sebastian Simon Nov 09 '22 at 18:13
  • where is the actual asynchronous operation? If you were to do an asynchronous call in the sort, that is going to be so slow. You need to rethink what you are trying to do. Storing the values first and looking them up would be the way to go, not making the same calls over and over. – epascarello Nov 09 '22 at 18:15
  • 1
    What @SebastianSimon said. Also, remember that the sorting callback will be called multiple times, potentially several times for the same element. E.g. if you have `[a, b, c, d]` you might get `sortCallback(a, b)` `sortCallback(a, c)`, `sortCallback(d, a)`. If each requires feching the same data and comparing it, then you might be better off doing something like `sorting = await Promise.all(arr.map(x => getDataForComparing(x)); arr.sort((a, b) => sorting[a] - sorting[b]` or otherwise pre-compute the values that will be used for sorting. – VLAZ Nov 09 '22 at 18:16
  • 1
    Never use `return await`, that's an anti-pattern. – vitaly-t Nov 09 '22 at 18:37
  • 1
    You cannot sort asynchronously, because you need a complete data set for that. This means you need to use `Promise.all`, and then apply regular sync `sort` on the resolved array of data. – vitaly-t Nov 09 '22 at 18:41
  • @SebastianSimon function f(a, b) that is passed to sort is NOT an async function but a synchronous function that's why I don't understand why it does not work. – user310291 Nov 09 '22 at 18:50
  • 2
    @user310291 because `test(a, b).then` returns a Promise – Andrew Parks Nov 09 '22 at 18:51

1 Answers1

1

The sort test function potentially gets called many more times than there are values in the array. Therefore, you'd want to retrieve all values from the read function first.

Even if performance was not a problem, array.sort does not support an async test function.

async function read(p) {
  if(p === 'a') return 'aaaaaaaaaaaaaaaaa';
  if (p === 'b') return 'bbbbbbbb';
}

(async () => {
  let ids = ['a', 'b'];
  (await Promise.all(ids.map(id=>read(id))))
    .forEach((v,i) => ids[i] = {id:ids[i], v});
  ids = ids.sort((a,b) => a.v.length - b.v.length).map(i=>i.id);
  console.log(ids);
})();
Andrew Parks
  • 6,358
  • 2
  • 12
  • 27