I am trying to understand a code from socket.io/examples/chat/app.js.
I am not able to explain what the fn() calls mean in the lines 71 and 73.
I guess it is a callback function but where is its definition?
Is it a short invocation of another function from app.js ?...
Is it a call of a prototype function of the socket object?
The fragment is (lines 69-78):
[...]
socket.on('nickname', function (nick, fn) {
if (nicknames[nick]) {
fn(true);
} else {
fn(false);
nicknames[nick] = socket.nickname = nick;
socket.broadcast.emit('announcement', nick + ' connected');
io.sockets.emit('nicknames', nicknames);
}
});
[...]
fn is passed in as an argument to the callback function, right here:
socket.on('nickname', function (nick, fn) {
^^
Since JavaScript functions are objects, they can stored in variables — and passed as arguments into other functions.
The use of the callback function in this particular case is duscussed in the “Getting acknowledgements” section of the Socket.IO docs — calling it with some data sends a message back to the client as a response to that message.
fn is a reference to another function that is being called from within the on nickname event.
IN javascript, functions are treated as objects so they can pass as an argument with in a callback function.
Related
I'm new to javascript and have been following this tutorial series on how sockets work: https://www.youtube.com/watch?v=HZWmrt3Jy10.
He writes:
var io = socket(server);
io.sockets.on('connection', newConnection);
function newConnection(socket){
console.log('new connection' + socket.id);
}
How does newConnection work in the sockets.on? It needs a socket parameter yet it works, it is a reference to the function as well. I have heard of callbacks vaguely but am still confused. Can someone please explain what is happening.
Functions in Javascript are "first class" objects and they can be passed around, stored in variables etc... consider this simple example:
function foo(x) {
console.log("foo(" + x + ") called");
}
function bar(f) {
f(42);
}
bar(foo);
last line calls the function bar passing it as a parameter the function foo. The function bar then calls the function f that it received passing 42 as argument.
The net result will be the message foo(42) called appearing in console.
In the code you show what happens is that the on function will store away the argument to call it later (providing the socket as parameter) once a connection is established.
You are passing your function so the socket.on method just like you would be passing a variable. And just like a variable, the code inside socket.on can then use your function including passing you the required parameter.
The socket.on() method would be implemented something like this:
Socket.prototype.on = function (event, callback) {
// other logic
callback(socket); // pass socket to your newConnection function
}
So when you call:
io.sockets.on('connection', newConnection);
you are passing your function newConnection as a callback (this can be named anything by the programmer who wrote socket.on) and then it will call your function as:
callback(socket); // callback is second parameter so
// in your case it is pointing to
// newConnection
so it passes the socket to your function.
I found the following example in ngResource documentation:
var cards = CreditCard.query(function() {
// GET: /user/123/card
// server returns: [ {id:456, number:'1234', name:'Smith'} ];
var card = cards[0];
// each item is an instance of CreditCard
expect(card instanceof CreditCard).toEqual(true);
card.name = "J. Smith";
// non GET methods are mapped onto the instances
card.$save();
// POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'}
// server returns: {id:456, number:'1234', name: 'J. Smith'};
// our custom method is mapped as well.
card.$charge({amount:9.99});
// POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'}
});
As I can understand, the second parameter of function query() is a function, which evaluated on success result of resource query. But simultaneously, this function takes the variable cards which is assigned from result of function query().
I can't understand, if this is normal to Javascript, since every async operation executes single thread?
Or special efforts were taken by creators of AngularJS in order to have function paramater executed after it's result returned?
How would I write my own function
function myfunction(argument, runbefore, runafter) {
runbefore();
POSTPONE runafter();
return Math.sin(argument);
}
which would execute 2nd parameter before itself and 3rd parameter -- after itself?
If I understand right, you are asking how it is possible for the callback function to be called after the return statement. One way that this is possible is through builtin functions that call another function at a later time. Take this code for example:
function doItLater(arg1, callbackFn) {
setTimeout(1000, callbackFn);
return arg1;
}
This will return the same argument that it was passed, and the callback function will be called later (about 1 second after the function has already returned). There are other ways a callback function can be delayed. For example, with an XMLHttpRequest, a callback function can be called after an HTTP response has been received. You can also connect to user events, so that a function will be called when the user does something specific.
If you want a little clarification on how things like setTimeout work in a single-threaded environment, I would suggest reading this article by John Resig.
How does the callback in fs.readfile get called when using fs.readfile.bind(context,pathArgument) like so. //understandable because my task function knows the name of the callback parameter
async.series([function(callback){
//operation done callback()},...],finalCallback(err,result));
BUT
//not understandable
async.series([fs.someOperation.bind(null,firstArgument),...],finalCallback(err,esult))
I believe I understand partial application;however, it would look something like this. function(callback){ fs.someOperation(firstArgument, ????)}(asyncCallbackFunc) and then I have no idea how the second argument is called...
Thx, in advance for helping me clear this up.
All bind does is set the context of the callback. It is still a regular callback like any other. Except, it is explicitly told what this will be. Looks like in your case, it is set to null.
The bind function on function object allows you to set the context i.e the value of this inside the function body as well as allow you to create a partial function in case you pass some arguments while calling bind.
For example:
function add(a,b) {
console.log(this);
return a+b;
}
var newAdd = add.bind("hello world", 10);
The newAdd will be one argument function which gets added to 10 and the result is returned. Also when newAdd is called the "hello world" will be logged in console.
Now when your code says fs.readFile.bind(null, path) it means that the return function will be of one argument which is the callback for readfile i.e the return function will be of form function(callback) { ... } which is exactly what is required to be passed to async.series
The main idea in the code you posted is to create a partial function that accepts only callback so that it can be passed to async.series the null argument doesn't play any role but you need to pass a context argument to call bind function, hence a null is passed as context arg.
Does anyone know how to pass parameters to a callback function that you cannot alter?
So here is the code I'm trying to implement (It is a siesta testing method):
Base.js:
waitForComponentQueryVisible: function (parentNext, parameters) {
var th = this,
query = parameters.query,
scope = th,
callback = callFunct,
timeout = 10000;
//The function inside here (returnToParentTester(parentNext, parameters)) is from Base.js
callFunct = function () {
scope.returnToParentTester(parentNext);
}
this.test.waitForComponentQueryVisible(query, callback, scope, timeout);
},
The problem here is of two parts:
1. I cant get the scope just right so I can use the returnToParentTester method that is found in Base.js
2. I want to pass in parentNext into the method but cannot do that when defining it as a callback
this is the method I need to run as the callback:
Base.js:
returnToParentTester: function (parentNext, parameters) {
debugger;
if (parentNext) {
parentNext.call(undefined, parameters);
} else {
this.test.fail('--Developer Error-- undefined parentNext ' +
'variable. All the chains are going to fail');
}
},
I can't get the scope just right so I can use the returnToParentTester method that is found in Base.js
Use the call method to change the scope:
Base.returnToParentTester.call(myScope)
I want to pass in parentNext into the method but cannot do that when defining it as a callback
Use an anonymous function as a callback and pass parameters within its scope:
$("body").click(function(e){foo(e.target,bar,baz)})
then let it do the work:
function foo(myScope, next1, param1)
{
Base.returnToParentTester.call(myScope, next1, param1)
}
References
Fast JavaScript max/min
Mixins and Constructor Functions
Function.prototype.apply revisited
applyFunctionArguments - argument injection technique in JavaScript
Functional JavaScript, Part 3: .apply(), .call(), and the arguments object
I'm trying to build an API in JS that will perform some operations and then execute the callback that's registered in AS when it's done. Because it's an API, I am just providing a JS method signature for another developer to call in Flash. Thus, the callback name that's registered in the AS part of the code should be a parameter that's passed in to the JS API in order for JS to communicate back to Flash.
For example:
[AS3 code]
ExternalInterface.addCallback("flashCallbackName", processRequest);
ExternalInterface.call("namespace.jsFnToCall", flashCallbackName);
function processRequest(data:String):void
{
//do stuff
}
[JS code]
var namespace =
{
jsFnToCall: function(callback)
{
//Do stuff in this function and then fire the callback when done.
//getFlashMovie is just a util function that grabs the
//Flash element via the DOM; assume "flash_id"'s a global var
//Below does not work...it's what I'd be ideally be doing some how.
getFlashMovie(flash_id).callback(data);
}
};
Because the definition of the function is in AS, I can't use the window[function name] approach. The only way I can think of is to build the callback in a string and then use the eval() to execute it.
Suggestions? T.I.A.
Well, I can think of one thing I would try, and one thing that would work.
What I would try first.
getFlashMovie(flash_id)['callback'](data);
What would work: Have the callback always be the same, say callback. The first parameter to the callback could be used to determine what actual function to call in flash. For example:
function callback($fn:String, $data:*) {
// either
this[$fn]($data);
// or
switch ($fn) {
case "callback1":
DoSomeCallback($data);
break;
}
Additionally passing the objectID makes it a bit simpler:
ExternalInterface.addCallback("flashCallbackName", processRequest);
ExternalInterface.call("namespace.jsFnToCall", ExternalInterface.objectID, "flashCallbackName");
Then in your JS:
var namespace =
{
jsFnToCall: function(objectID, callback)
{
//Do stuff in this function and then fire the callback when done.
document[objectID][callback](data);
}
};