1

I'm writing a library that takes user-defined functions. I don't have control over what they do, but I want to catch all errors that they cause.

They might also make asynchronous calls like setTimeout, which might throw Errors. I want to catch those errors too.

For example—

// Suppose this is passed as an argument to the module
var userFunction = function() {
    setTimeout(function() { throw Error("fail") }, 200);
}

// This is module code
try {
    userFunction();
} catch (e) {
    console.log("Caught error");
}

—fails with an error and prints a stack trace. The catch doesn't trigger.

I can see how this happens: The error is thrown from the function passed to setTimeout, which is called after the try-catch has passed, in a different context.

How do I work with that? Is it even possible?

If given a function that might call setTimeout or other asynchronous processes within it, how can I catch errors they might throw?

3 Answers3

2

You can use window.onerror to catch all error

try {
    setTimeout(function() { throw Error("fail") }, 2000);
} catch (e) {
    console.log("Caught");
}

window.onerror = function (){
  document.body.innerHTML = "Test";
}

or you can use try catch inside async method

setTimeout(function() {
       try {
          throw Error("fail");
       } catch (e) {
        console.log("Caught");
    }
    }, 2000);
Anoop
  • 23,044
  • 10
  • 62
  • 76
  • The first catches *all errors*; also those from my code and all libraries I'm using, with no way to distinguish them, which would cause more problems than it fixes. The second means I need to tell my library's users to wrap every async call they make in a try-catch, which results in lots of repetition that makes a mess of their functions. – Anko - inactive in protest Jul 20 '15 at 14:49
  • @Anko you can use Promise instead of using callback. there you can catch the exception. – Anoop Jul 20 '15 at 14:55
  • If it doesn't involve changing the passed-in user functions, I'd appreciate an explanation of how to do that. – Anko - inactive in protest Jul 20 '15 at 15:00
0

You can use Promises.

With jQuery, something like:

var dfd = jQuery.Deferred();

setTimeout(function() {
  dfd.reject("some error msg");
}, 1000);

$.then(dfd.promise()).then(function() {
//blank, this is success callback
}, function(msg) {
//throw your error
});

Full doc: https://api.jquery.com/deferred.promise/

EDIT: can use any Promise implementation. Such as kriswowal/q https://github.com/kriskowal/q

Christian Benseler
  • 7,907
  • 8
  • 40
  • 71
  • That involves adding jQuery as a dependency for my library and requiring users to also have jQuery as a dependency so they can pass in appropriately formatted functions. Is there no way to do this in plain JS? – Anko - inactive in protest Jul 20 '15 at 15:03
  • You don't have to use jQuery. I just used it in the example.You can implement your own Promise library. Discussed here: http://stackoverflow.com/questions/18422021/how-do-promises-work-in-javascript – Christian Benseler Jul 20 '15 at 15:29
0

You don't need to include jQuery. You can use javascripts built in Promise object:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/prototype

you have:

y = x;

x returns a promise:

function() {
    ...
    return promise;
}

All of the asynchronous calls in x are layered:

x is last async handler:

x = function () {
    ...
    // a is second to last async success handler etc..
    var j = new Promise (a);

    j.then(function() {
        // a returned resolve
        if (some successful condition) {
            resolve(what ever arguments you want to pass y);
        } else {
           reject(what ever arguments you want to pass y);
        },
        function (e) {
            // error returned by a
            reject(e);
        }
    );
    return j;
};

then you can do:

y.then(function() {},
    function() {
        console.log("Caught");
    }
);
mpdunson
  • 227
  • 1
  • 11