73

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.

0

5 Answers 5

101

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)
Sign up to request clarification or add additional context in comments.

2 Comments

solid answer; maybe instead of "are executed in the main loop" write "are executed in the event loop (scheduled as macrotasks)", that is closer to the common JavaScript terminology (I believe; at least searching for these words yields good results for deeper details)
This is a stunning answer! It includes solution that works with great theory. It also answers a lot of questions of how to handler error in promises.
38

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)   
})

4 Comments

This should be the accepted answer (hint, hint @Andrew Kochnev) since it actually explains why and is most thorough.
you may end with corrupted nodejs process. Do not handle uncaught exceptions without killing the process. nodejs.org/api/…
isn't try catch inside settimeout doing same thing as process.on .. but nice answer
Also try catch will give proper error stack..
4

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)

Comments

3

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);

Comments

0

When we have try/catch block, the code inside "try" block gets executed in that instant. When we have await syntax inside try/catch execution halts when the await line runs. In your code example, when setTimeout code gets executed, we are not in try/catch block anymore.

One way to handle is to use setTimeout from timers/promises. In test.mjs file, write this and execute with node test.mjs

import { setTimeout } from "timers/promises";

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.