views:

259

answers:

4

Hello everybody!

Would it be faster to just put code inside a try-catch block instead of performing various error checks?

For example..

function getProjectTask(projectTaskId) {
    if (YAHOO.lang.isUndefined(projectTaskId) || YAHOO.lang.isNull(projectTaskId) && !YAHOO.lang.isNumber(projectTaskId)) {
        return null;
    }

    var projectPhaseId, projectPhaseIndex, projectTaskIndex, projectPhases, projectPhase, projectTask;

    if (!YAHOO.lang.hasOwnProperty(projectTaskPhaseMap, projectTaskId)) {
        return null;
    }

    projectPhaseId = projectTaskPhaseMap[projectTaskId];

    if (YAHOO.lang.isUndefined(projectPhaseId) || YAHOO.lang.isNull(projectPhaseId) || !YAHOO.lang.hasOwnProperty(scheduleData.ProjectPhasesMap, projectPhaseId)) {
        return null;
    }

    projectPhaseIndex = scheduleData.ProjectPhasesMap[projectPhaseId];
    if (YAHOO.lang.isUndefined(projectPhaseIndex) || YAHOO.lang.isNull(projectPhaseIndex) || !YAHOO.lang.hasOwnProperty(scheduleData.ProjectPhases[projectPhaseIndex])) {
        return null;
    }
    projectPhase = scheduleData.ProjectPhases[projectPhaseIndex];

    if (!YAHOO.lang.hasOwnProperty(projectPhase.ProjectTasksMap, projectTaskId)) {
        return null;
    }

    projectTaskIndex = projectPhase.ProjectTasksMap[projectTaskId];

    if (YAHOO.lang.isUndefined(projectTaskIndex) || YAHOO.lang.isNull(projectTaskIndex)) {
        return null;
    }

    projectTask = scheduleData.ProjectTasks[projectTaskIndex];
}

VS

function getProjectTask(projectTaskId) {
    try {
        projectPhaseId = projectTaskPhaseMap[projectTaskId];
        projectPhaseIndex = scheduleData.ProjectPhasesMap[projectPhaseId];
        projectPhase = scheduleData.ProjectPhases[projectPhaseIndex];
        projectTaskIndex = projectPhase.ProjectTasksMap[projectTaskId];
        projectTask = scheduleData.ProjectTasks[projectTaskIndex];

    }
    catch (e) {
        return null;
    }
}

I hope my question makes sense. I would be happy to clarify. Thank you!

+4  A: 

"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 to readable code. The key thing to remember is:

Avoid try-catch in performance-critical inside 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? :)

galambalazs
Well put. I'd just like to add that unless you actually have a performance problem, it's best to make your code readable. When you actually do have a performance problem, first measure where the problem is, only then optimize. Otherwise you may spend much time optimizing the wrong things.
Jani Hartikainen
+2  A: 

Sure, it makes for more compact code, but it reduces your debug ability and makes adding graceful error-recovery, or useful error messages much, much, harder.

Brock Adams
A: 

Keep in mind that this varies based on browsers as well but overall I have not read anything about significant performance penalties for using a try/catch block. But it's not exactly a good practice to get into using them because you are not able to tell why a problem failed.

Here is an interesting slide show of some javascript performance considerations. On slide 76 they cover try/catch blocks and the performance impact. http://www.slideshare.net/madrobby/extreme-javascript-performance

spinon
A: 

Depends on the situation. As galambalazs mentions readability is important. Consider:

function getCustomer (id) {
  if (typeof data!='undefined' && data.stores && data.stores.customers 
      && typeof data.stores.customers.getById=='function') {
    return data.stores.customers.getById(id);
  } else {
    return null;
  }
}

compared to:

function getCustomer (id) {
  try {return data.stores.customers.getById(id);} catch (e) { return null; }
}

I'd say the second is much more readable. You tend to get data back like this from things like google's apis or twitter's feeds (usually not with deeply nested methods though, that's just here for demonstration).

Of course, performance is also important, but these days javascript engines are fast enough that nobody's likely to notice a difference, unless you're going to call getCustomer every ten milliseconds or something.

no