I am trying to work out how to implement an asynchronous callback in node given that I don't know what the arguments could be.
I'll state the sync version of what I'm trying to do so as to make this clearer.
function isAuthorized(userID){
// check for user Permissions here
return isAuthorized;
}
Using this any function can call it and, from the value it returns, determine if the user is authorized. However, the function that I use to get the userID (and check for permissions) are both asyncronous functions and require callbacks. However I have no idea how to get this implemented when I don't know the arguments needed in the callback.
The function that calls this could want to send an number of arguments to the callback (normally it'd just wait for a return in sync) and that's what's confusing me.
function isAuthorized(socket, callback, args){
socket.get('userID', function (err, userID) {
//check userID for permission
callback(args);
});
}
I realize I could convert the arguments into an array and send that array, but I wanted to know if there is a more general way to do this that doesn't force me to make all my callbacks convert from an array of arguments.
Hope you can help, Pluckerpluck
I'm not sure, if I understand you the right way, but it seems you're looking for the arguments
object in a function (MDN link).
Basically that way you don't have to specify any parameters in advance, but have the function look for what parameters are present. So you can do something like the following:
function myFunc() {
for (var i=0; i<arguments.length; ++i ) {
console.log( arguments[i] );
}
}
Which results in outputs like
myFunc( 1 );
> 1
myFunc( 's', 3, 'S' );
> "s"
> 3
> "S"
You can always create a function to pull those arguments into an array for you, and then reuse it in each of your async functions:
function asyncWithCallbackArgs(obj, callback) {
var args = Array.prototype.slice.call(arguments, 2);
callback.apply(obj, args);
}
This will then enable you to do things like this:
function callback (c, d, e, f) {
console.log([c, d, e, f]);
}
asyncWithCallbackArgs({}, callback,'c','d','e','f');
There's a fiddle here to play with.
So when you build an API, you specify what order the arguments are passed into the callback. So, you will want to comment your code well so that anyone who uses your API can understand what they will be getting back from your method.
It almost sounds like you are perhaps wanting to pass back different arguments, depending on what the passed in callback function looks like. That isn't traditionally how an API works. It would take a considerable amount of time to do that effectively.
I would recommend passing an object to the callback. The Object can have multiple arguments that people can pull out of it. This would ease future enhancement, as you could very simply add an additional property to that object without messing up everyone's implementation of your method. So, return something like this :
{
"id": "Some_ID",
"message": "Some Message",
"isAuthorized" : true
}
This way anyone who uses your API doesn't have to account for multiple arguments in the callback method. They know that they are only going to get one arg, and that it will be an Obj with multiple properties, and they can consume which properties they want. Further, in the future you can add a 4th or 5th property without breaking their code. You could add a "datetime" property, and their code would remain unchanged. You would get backwards compatibility, and new implementors could then use the new properties.
If I'm understanding you correctly, don't pass them as arguments at all:
var a = "something";
var b = "something";
var callback = function(){
// use a and b here
};
isAuthorized(socket, callback);
In Coffee-script you have something called splats.
( socket, callback, args... )->
callback args...
This translates as the following in Javascript:
var __slice = [].slice;
function() {
var args, callback, socket;
socket = arguments[0], callback = arguments[1], args = 3 <= arguments.length ?__slice.call(arguments, 2) : [];
return callback.apply(null, args);
};