开发者

What is the more correct position for the error argument in a javascript callback?

开发者 https://www.devze.com 2023-03-06 15:06 出处:网络
I am writing a javascript function that takes a callback. The callback will be passed an error argument if something goes wrong.

I am writing a javascript function that takes a callback. The callback will be passed an error argument if something goes wrong.

What are the best / most standard calling conventions?

  • Should the callback's error argument be first or last?
  • Should I pass an 'errorMsg' string, or a new Error('errorMsg') object?

Ie, what is more correct - this code:

foo = function(bar, callback) {
  ...
  if (error) {
    callback('troz not found');
  } else {
    callback(null, result);
  }
}
开发者_开发技巧

or this code:

foo = function(bar, callback) {
  ...
  if (error) {
    callback(null, 'troz not found');
  } else {
    callback(result);
  }
}

or this:

foo = function(bar, callback) {
  ...
  if (error) {
    callback(null, new Error('troz not found'));
  } else {
    callback(result);
  }
}

If its relevant, my code will be used as both as a NodeJS module and as a browser-based javascript library.


You could specify two callbacks, one for success and one for error, and both encapsulated in a single "callbacks" argument. This is how many Javascript libraries handle your requirement.

var fooFn = function(bar, callbacks) {
  callbacks = callbacks || {}; //make callbacks argument optional
  ...
  if (error) {
    if (callbacks.error) {
      callbacks.error('troz not found'); //pass the error message as a string
    }
  } else if (callbacks.success) {
    callbacks.success(result);
  }
}

The success and error functions are optional. To specify both, call it like this:

fooFn("some bar", {
  success: function(result) {
    //success :-)
  },
  error: function(errorMsg) {
    //error :-(
  }
});

You can also do this:

fooFn("some other bar");

If you like, you can expand the callbacks object to support other scenarios, like "complete".


Most node.js apps either use the 'error-first' pattern or the EventEmitter pattern. viz:

// more common
if (error) {
  cb({make:'better'})
} else {
  cb(undefined, stronger)
}

or

// cleaner, perhaps, but more keystrokes
var ee = new EventEmitter
process.nextTick(function () {
  ...
  if (error) {
    ee.emit('error', {msg:'delicious'})
  } else {
    ee.emit('success', bacon)
  }
})
return ee


You should choose a convention for your library and stick with it; otherwise, it is arbitrary. There are many different ways of handling errors in JavaScript:

  1. Taking both a "success" and "error" callback.
  2. Taking a single callback to handle both "success" and "error" cases.
  3. Having a registration mechanism for a default "error" handler, making error handlers optional on all other calls, using the immediate or fallback error callbacks as appropriate.

Combined with:

  1. Using no parameters to the error callback.
  2. Using a boolean to indicate success / failure.
  3. Using a string to encapsulate the nature of the error.
  4. Using some more complex "Result" object to encapsulate success/failure and the result.
  5. Using some complex object to encapsulate detailed failure information.

Really, it's entirely up to you. It also depends on what you are trying to do. For example, if you don't really intend to do anything with the failure information, then it might not be worth the expense of constructing / passing around that extra information. But perhaps you have lots of detailed failure information you want to pass to the user or back to the API caller, in which case it makes lots of sense.

Choose a convention, and stick with it. Other than that, it's entirely up to you.


Seems we have lack of modern response here :)

Now you can use Promise for it:

foo = function (bar) {
    return new Promise(function (resolve, reject) {
        ...
        if (error) {
            reject('troz not found');
        } else {
            resolve(result);
        }
    });
}

or simpler, if action is synchronous:

foo = function (bar) {      
    ...
    if (error) {
        return Promise.reject('troz not found');
    } else {
        return Promise.resolve(result);
    }
}

and then, to handle result:

foo.then(callback)
   .catch(errorHandler);

where

callback = function (result) {...}
errorHandler = function (errorMessage) {...}

so that, in case there was no error callback(result) will be done, in case of error errorHandler('troz not found') will be done.

As additional benefit - having result handler and error handler separately. Nice example of separation of concerns.

0

精彩评论

暂无评论...
验证码 换一张
取 消