javascriptasynchronouspromiseasync-await

How to add a time limit to a JS Promise resolve (reject Promise on timeout)?


Currently trying to teach myself how Promises work in JavaScript.

So I want to create a Promise in which I do a complex calculation. If that calculation completes successfully in time I want the Promise to resolve, but if the calculation takes too long the Promise should reject with a timeout error. The available time is predefined, e.g. 1000ms.

My sample code looks like this:

new Promise((resolve, reject) => {
  const result = complexCalculation();
  return resolve(result);  //this should be called when complexCalculation completed in under 1000ms
  return reject('timeout error');  //and this if 1000ms have passed without getting a result
})
.then(result => {
  console.log(result);
})
.catch(err => {
  console.log(err);
});

I tried different things already like an async function and setTimeout, but none of it worked the way I tried to implement it. I'm still very new to JS in general so please bear with me.


Solution

  • Here is an example of how to set up a promise with a timeout reject:

    function calcWithTimeout(timeout) {
    
      return new Promise((resolve, reject) => {
      
        // start timeout
        const timeoutID = setTimeout(
          () => reject('longCalculation took too long'),
          timeout
        );
        
        // start calculation
        longCalculation().then(result => {
          clearTimeout(timeoutID);
          resolve(result);
        });
      });
      
    }
    
    // a fake calculation that takes 1 second
    function longCalculation() {
      return new Promise(resolve => {
        setTimeout(() => {
          resolve('your calculation completed');
        }, 1000);
      });
    }
    
    const pre = document.getElementById('result');
    
    const myFn = (timeout) => {
      pre.innerHTML = 'calling calcWithTimeout with timeout = ' +
        timeout + '\n';
      
      calcWithTimeout(timeout)
      .then(result => {
        pre.innerHTML += 'result: ' + result;
      })
      .catch(err => {
        pre.innerHTML += 'error: ' + err;
      });
    }
    #result {
      background-color: #eee;
      padding: 0.5rem;
    }
    <button onclick="myFn(2000)">Long Timeout</button>
    <button onclick="myFn(500)">Short Timeout</button>
    <pre id="result"></pre>