0

Hello is there any solution to order promises by execution time? for ex

Promise.all([Promise // 5ms ,Promise // 3ms,Promise // 2ms])

will return answer with same order as it was given is there any solution or method to sort it by execution time to have return like?

Promise.all([Promise // 2ms ,Promise // 3ms,Promise // 5ms])

3 Answers3

1

To restate the problem clearly: given a set of promises, can they be executed concurrently, and can the results be arranged in an array in order of execution time?

If the execution time is known in advance, then sort the promises by execution time and pass the sorted array to Promise.all().

If the execution times are unknown in advance, I'd suggest wrapping the promises with a little function that times execution. Sort the result of Promise.all() on those elapsed times...

function sortedPromiseAll(array) {
  const start = new Date()
  const instrumentPromise = p => {
    return p.then(result => {
      const now = new Date();
      return { result, duration: now.getTime()-start.getTime() }
    });
  }
  const instrumentedPromises = array.map(instrumentPromise)
  return Promise.all(instrumentedPromises).then(results => {
    return results.sort((a, b) => a.duration-b.duration).map(r => r.result);
  })
}

const timedPromise = t => {
  return new Promise(resolve => {
    setTimeout(resolve, t)
  })
};

// imagine we don't know these timings
const promiseA = timedPromise(600).then(() => 'A');
const promiseB = timedPromise(300).then(() => 'B');
const promiseC = timedPromise(900).then(() => 'C');

// expected result is B, A, C
sortedPromiseAll([promiseA, promiseB, promiseC])
  .then(result => console.log(result));
danh
  • 62,181
  • 10
  • 95
  • 136
  • I'd even recommend to move the `const start = new Date()` outside of the `instrumentPromise` function so that there's only one start date shared by all instrumentations. – Bergi Dec 22 '21 at 19:49
  • Good idea. Thanks, @Bergi. – danh Dec 22 '21 at 20:20
0

You can get the ordering of when they resolve if you manually push the results of each promise into an array. In this example the value resolved is a string that shows the timestamp it was added.

Results are pushed into outputs array when they resolve. Printing outputs shows they are now ordered based on when they resolved.

const outputs = [];

function createPromise() {
  return new Promise((resolve, reject) => {
    // adding a bit of randomness here so there is no guarantee when they resolve
    const delay = Math.random() * 1000;
    setTimeout(() => {
      resolve(`Promise resolved at ${Date.now()}`);
    }, delay);
  });
}

function addResult() {
  return createPromise().then(value => {
    outputs.push(value);
  });
}

Promise.all([addResult(), addResult()]).then(() => console.log(outputs));
GenericUser
  • 3,003
  • 1
  • 11
  • 17
  • Avoid the [`Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it) in `addResult`! – Bergi Dec 22 '21 at 19:33
  • @Bergi If `addResult` was nothing more than calling `createPromise` I would agree. However, this setup is intention to populate `outputs`. – GenericUser Dec 22 '21 at 19:45
  • So? You still don't need a `new Promise` to do `outputs.push(value)` in a `.then()` callback. – Bergi Dec 22 '21 at 19:46
  • If `createPromise` is used elsewhere, automatically adding its result to output may be undesired in those other locations. If its only purpose is in this body, the updating of `outputs` can certainly be adjusted. – GenericUser Dec 22 '21 at 19:53
  • 1
    I never said to modify the code of `createPromise`. You should just drop the `new Promise` from `addResult` and simply `return createPromise().then(value => { outputs.push(value); });` – Bergi Dec 22 '21 at 19:57
  • 1
    @Bergi I misunderstood, thanks for clarifying. Adjusted accordingly. – GenericUser Dec 22 '21 at 20:07
0

The easiest way is to push them to a new array as they come in. No need to create extra promises, just have to piggyback off the promise that is already created.

const getRandomPromise = () => {
  return new Promise(resolve => {
    var ms = Math.random() * 3000;
    window.setTimeout(()=>resolve(ms), ms);
  });
};


function orderPromises (promises) {
  const orderedPromies = [];
  const pushPromiseResults = promise =>
    promise.then(result => (orderedPromies.push(result), result))

  promises.forEach(pushPromiseResults);
  return Promise.all(promises).then(()=>orderedPromies);
}

const myPromises = [getRandomPromise(), getRandomPromise(), getRandomPromise()];

orderPromises(myPromises).then(x => console.log(x));
epascarello
  • 204,599
  • 20
  • 195
  • 236
  • Using `forEach` instead of `map` and ignoring the promises resulting from the `.then()`calls instead of calling `Promise.all` on them will cause unhandled rejections if any of the promises rejects. – Bergi Dec 22 '21 at 22:32