Search code examples
es6-promiseasynchronous-javascript

implement a promise to return the slower of two promises


I'm new to asynchronous programming and I'm only getting familiar with the idea of promises as a replacement for callbacks. I'm trying to implement a function ( promise) to take in two other promises, and that will return the value of the one that took longer to complete only if both completed. So basically my idea was to use the Date.now() function to calculate the time it takes for one promise to execute, but I'm having trouble writing it down, especially with a promise that takes in two other promises ( if that's even possible), here's my attempt:

var p1 = new Promise((resolve, reject) => {
let start = Date.now();
setTimeout(() => 
   resolve(
     {
       id: 0,
       time: Date.now() - start,
       value: 4+3
     }
           ), 500);
})

var p2 = new Promise((resolve, reject) => {
  let start = Date.now();

  setTimeout(() => 
    reject(
      {
        id: 1,
        time: Date.now() - start,
        value: 7+3
      }
          ), 800);
})

This is just an idea, and the promises p1, p2 should be given as arguments to the promise 'slower', the thing I did with Date.now() should somehow be wrapped around the call to these promises, and then I'm hoping to calculate the runtime of both promises and then return the value of the slower one. Any ideas on how to implement this? Thanks.


Solution

  • Here's one idea for how to do it. Rather than timestamps, I just used a cntr. The last one (the slowest one) will be tagged with cntr === 0 so when they're all done, we just fine that one that is tagged with the 0 cntr and return it's val.

    function promiseSlowAll(arrayOfPromises) {
        let cntr = arrayOfPromises.length - 1;
        let newPromises = arrayOfPromises.map(p => {
            return p.then(val => {
                // wrap the results in an object along with a cntr
                return {val: val, cntr: cntr--};
            });
        });
        return Promise.all(newPromises).then(allResults => {
            const lastResult = allResults.find(item => item.cntr === 0);
            // resolve with a single result from the last promise to finish
            return lastResult.val;
        });
    }
    

    So, you call promiseSlowAll() with an array of promises and you get back a single resolved value that corresponds with the slowest promise to resolve.

    Here's a working demo:

    function promiseSlowAll(arrayOfPromises) {
        let cntr = arrayOfPromises.length - 1;
        let newPromises = arrayOfPromises.map(p => {
            return p.then(val => {
                // wrap the results in an object along with a cntr
                return {val: val, cntr: cntr--};
            });
        });
        return Promise.all(newPromises).then(allResults => {
            const lastResult = allResults.find(item => item.cntr === 0);
            return lastResult.val;
        });
    }
    
    function delay(t, v) {
        return new Promise(resolve => {
            setTimeout(resolve, t, v);
        });
    }
    
    promiseSlowAll([delay(200, "200"), delay(300, "300"), delay(100, "100")]).then(r => {
        console.log("slowest is", r);
    });