Javascript Try-Catch Performance Vs. Error Checking Code Javascript Try-Catch Performance Vs. Error Checking Code javascript javascript

Javascript Try-Catch Performance Vs. Error Checking Code


"Programs must be written for people to read, and only incidentally for machines to execute."

Abelson & Sussman, SICP, preface to the first edition

Always aim for readable code. The key thing to remember is:

Avoid try-catch in performance-critical functions, and loops

Anywhere else they won't do much harm. Use them wisely, use them sparingly. As a side note if you want to support older browsers they may not have try-catch.

But as I see you clearly misuse some functions for error checking. You can test for the desired objects and properties of objects right before you use them instead of complex checking. And:

if (YAHOO.lang.isUndefined(projectPhaseId) || YAHOO.lang.isNull(projectPhaseId))

can be written as

if (projectPhaseId != null)

for example... So the example above can be fairly readable even without try catches. You seem to misuse YUI a bit.

I would bet this works as expected:

function getProjectTask(projectTaskId) {   var projectPhaseId    = projectTaskPhaseMap[projectTaskId],       projectPhaseIndex = scheduleData.ProjectPhasesMap[projectPhaseId],       projectPhase      = scheduleData.ProjectPhases[projectPhaseIndex];  if (projectPhase == null) return null; // projectPhase would break the chain  var projectTaskIndex  = projectPhase.ProjectTasksMap[projectTaskId],      projectTask       = scheduleData.ProjectTasks[projectTaskIndex];   return projectTask || null; // end of the dependency chain}

How cool is that? :)


Why not have a fact basis for the argument? The following code demonstrates the performance impact:

var Speedy = function() {    this.init();};Speedy.prototype = {    init: function() {        var i, t1;        this.sumWith = 0;        this.sumWithout = 0;        this.countWith = 0;        this.countWithout = 0;        for (i = 0; i < 5; i++) {            t1 = this.getTime();            console.log("Using Try/Catch, Trial #" + (i + 1) );                        console.log("started " + t1 );            this.goTry(t1);            this.countWith++;        }        for (i = 0; i < 5; i++) {            t1 = this.getTime();            console.log("W/out Try/Catch, Trial #" + (i + 1) );            console.log("started  :" + t1 );            this.goAlone(t1);            this.countWithout++;        }        for (i = 5; i < 10; i++) {            t1 = this.getTime();            console.log("Using Try/Catch, Trial #" + (i + 1) );            console.log("started  :" + t1);            this.goTry(t1);            this.countWith++;        }        for (i = 5; i < 10; i++) {            t1 = this.getTime();            console.log("W/out Try/Catch, Trial #" + (i + 1) );            console.log("started  :" + t1);            this.goAlone(t1);            this.countWithout++;        }        console.log("---------------------------------------");        console.log("Average time (ms) USING Try/Catch: " + this.sumWith / this.countWith + " ms");        console.log("Average time (ms) W/OUT Try/Catch: " + this.sumWithout / this.countWithout + " ms");        console.log("---------------------------------------");    },    getTime: function() {        return new Date();    },    done: function(t1, wasTry) {        var t2 = this.getTime();        var td = t2 - t1;        console.log("ended.....: " + t2);        console.log("diff......: " + td);        if (wasTry) {            this.sumWith += td;        }        else {            this.sumWithout += td;        }    },    goTry: function(t1) {        try {            var counter = 0;            for (var i = 0; i < 999999; i++) {                counter++;            }            this.done(t1, true);        }        catch (err) {            console.error(err);        }    },    goAlone: function(t1) {        var counter = 0;        for (var i = 0; i < 999999; i++) {            counter++;        }        this.done(t1, false);    }};var s = new Speedy();

This JSFiddle will show you the output in firebug lite's console: http://jsfiddle.net/Mct5N/


Placing dogma aside and not being satisfied with the answers here at the moment...

If your code rarely throws exceptions, placing a try-catch around the offender performs well because there is no additional overhead in catching the exception or preventing it.

If the code commonly throws exceptions based on unpredictable data or some scenario similar to that, placing a guard method increases performance considerably, up to 20 times if exceptions occur often.

If I were to advise an approach, use simple guard operators when possible if there isn't deep nesting. In cases of deeper nesting, use a guard method that can traverse through as needed.

Here's some testing of my own that I based this off of.

http://jsfiddle.net/92cp97pc/6/

Scenarios are comparing the following but in loops:

var a;// scenario 1 (always throws/catches)try { a.b.c.d; }catch(ex) { }// scenario 2 (about 20 times faster than scenario 1)guard(a, 'b', 'c', 'd');// now no exceptions will occura = { b: { c: { d: true } } };// scenario 3 (too fast to measure)try { a.b.c.d; }catch(ex) { }// scenario 4 (.04 times slower than scenario 3)guard(a, 'b', 'c', 'd');