How to handle errors from setTimeout in JavaScript?

Javascriptnode.jsAsynchronous

Javascript Problem Overview


Simple question about try/catch for function in setTimeout

try {
    setTimeout(function () {
        throw new Error('error!');
    }, 300)
} catch (e) {
    console.log('eeee!')
    console.log(e)
}

Why doesn't catch block work?

What can I read about this?

P.S: the question is about possibility of handling errors like this. Don't answer about promises.

Javascript Solutions


Solution 1 - Javascript

Functions scheduled to run with setTimeout are executed in the main loop, outside the body of code that originated them.

To handle errors, put the try-catch inside the setTimeout handler:

setTimeout(function () {
  try {
    throw new Error('error!');
  } catch (e) {
    console.error(e);
  }
}, 300)

If you need to access the Error object from block that called setTimeout, use Promises:

const promise = new Promise((resolve, reject) => {
  setTimeout(function () {
    try {
      throw new Error('error!');
      resolve(); // if the previous line didn't always throw

    } catch (e) {
      reject(e)
    }
  }, 300)
})

promise
  .then(result => console.log("Ok " + result))
  .catch(error => console.error("Ouch " + error))

This example above is not the most elegant way of handling the case with a Promise. Instead, implement a delay(ms) function like this:

function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms))
}

Then call

delay(300).then(myFunction).catch(handleError)

Solution 2 - Javascript

You can find good explanation in this Node.js official doc.

The problem is that when the callback of your setTimeout() function executes the try { } catch(err) { } block is already exited. Also notice that the callback can crash Node.js process.

However if you want to handle the errors in the callback of setTimeout() function, then you can listen them by using process global EventEmitter object

process.on('uncaughtException', function(err){
  console.log(err)   
})

Solution 3 - Javascript

Because the catch block lexically surrounds the setTimeout call but that is not the function that throws. The direct translation, is

setTimeout(function () {
  try {
    throw new Error('error!');
  } catch (e) {
    console.log('eeee!');
    console.log(e);
  }
}, 300);

Solution 4 - Javascript

A bit strange solution, but sometimes it would be useful maybe...

function globalErrorHandler(e) {
  console.warn('eeee!')
  console.warn(e);
}

const _setTimeoutOriginal = setTimeout;
setTimeout = function(callback, timeout) {
  const args = Array.from(arguments).slice(2);
  _setTimeoutOriginal(function() {
    try {
      callback.apply(this, args);
    } catch (e) {
      globalErrorHandler(e);
    }
  }, timeout);
};

setTimeout(function() {
  throw new Error('error!');
}, 300)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAndrew KochnevView Question on Stackoverflow
Solution 1 - JavascriptslezicaView Answer on Stackoverflow
Solution 2 - JavascriptKarlenView Answer on Stackoverflow
Solution 3 - JavascriptAluan HaddadView Answer on Stackoverflow
Solution 4 - JavascriptДавид МанжулаView Answer on Stackoverflow