I've just started learning node.js and express and there's something that confuses me a bit in the "hello world" example on the express.js website. In the example, they refer to the server variable inside the callback function.
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('App listening at http://%s:%s', host, port);
});
Does app.listen() return a value to server variable before it executes the callback function? How can it do that and how does it work? Is this the same for all callback functions in node (and javascript)?
I would just like a simple explanation of the execution process.
To be clear, I understand that the callback function has access to the server variable. But if the app.listen method executes the callback function before it returns a value to the server variable, wouldn't that mean that the server variable is still underfined when you try to access server.adress()? That is what I don't understand.
Does app.listen() return a value to server variable before it executes the callback function?
Yes, exactly. app.listen() resembles to the plain Node.js server.listen method.
The callback is an shortcut for assigning the server an listener to the listening event.
You could do the same with the following code:
var server = app.listen( 3000 );
server.on( "listening", function () {
console.log( "server is listening in port 3000" );
});
How can it do that and how does it work? Is this the same for all callback functions in node (and javascript)?
This happens because IO events in Node.js are all run asynchronously (with exceptions from the fs module) - this is, they will only take place when other synchronous code have finished to run.
This works the same in browser JS - if you run some JS process synchronously, any events triggered (like click, blur, etc) will only execute after that one finishes.
A function has access to all the variables that existed in the scope where it was created (unless it masks them).
var in_the_global_scope = 1;
function outer() {
function inner() {
alert(in_the_global_scope);
}
inner();
}
inner has access to any variable declared in inner, outer and the global scope.
A function being a callback isn't really relevant.
The listen method itself doesn't have access to server because listen was created in a different scope.
But if it returns a value, how can it then execute the callback function?
Because it doesn't just execute the callback. It waits for an event and the callback gets fired in reaction to that.
var timeOutId = setTimeout(function() {
alert(timeOutId);
}, 1000);
var server is being assigned to the function app.listen()
If you look at the express documentation it states that
The app.listen() method is a convenience method for the following (for HTTP only):
app.listen = function() {
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
By setting var server = app.listen() and the fact that app.listen() returns something, you're essentially setting var server to whatever app.listen() return.
You can thinking like that, the app.listen() return an object server which include information of how to run the server, example port, address, like a paper of instructions. Then it go to run server.
When server was run, the application also add some remark on that instructions example porcessid
then server is also call callback function app.listen(port[, callback]). Withing that function, we can access server information back from instruction and remarks.
Related
One of my functions in the frontend is using ‘this’.
function myFunction() {
...
console.log(this);
...
}
I call it like this:
myFunction.call(objAsThis, param1, param2);
and everything is working as expected. But then I tried to pass this function to the backend(node.js) as a callback using socket.io:
Client
socket.emit("some event", param3, param4, myFunction);
Calling this function in node in the same way rendered some unexpected results.
Server
socket.on("some event", function(param3, param4, myCbFunction) {
...
myCbFunction.call(someObject, param5, param6);
...
});
I expect to see the someObject object printed but instead I get the socket.io's ‘this’ printed. Same story if I try to use bind:
myCbFunction.bind(someObject)(param5, param6);
I even tried(out of curiosity) calling it with new, which should have created a new object, but it didn't. Outcome remained as before.
new myCbFunction(param5, param6);
I get the same result(socket.io's this) if I just console.log(this) inside the “some event” event handler on the server.
So myCbFunction completely ignored the call, the bind or the new.
Can someone please explain what is going on? Why it's not binding this to the object I provide?
OK, I think I see a source of confusion.
When you register this on the server:
socket.on("some event", function(param3, param4, callback) {
...
callback(someArgs);
});
The point of callback() is to notify the client that you have received the message. It's referred to in the documentation as an ack function. This is NOT directly calling your client code. In fact, this callback function is something that socket.io provides and when you call it you're calling socket.io, not calling the client.
Instead, you call this function provided by socket.io and when socket.io receives this function call it packages up a message and sends that message back to the client over the socket.io connection. You call that ack function on the server when you want to tell the client that you've received the original message.
Keep in mind that client and server are nearly always on separate computers miles apart (always at oppositive ends of a TCP socket). You can't directly call client code from the server.
The client socket.io code will receive that ack message (and any serializable arguments you sent with it) and then will call the client side ack function that you specified here:
socket.emit("some event", param3, param4, myFunction);
You do not control the this value when this ack function is called - it will be whatever socket.io sets it to (unless you declare it as an arrow function). But, instead of passing your actual function, you can use a stub function and then reattach the desired this value before calling your real function.
socket.emit("some event", param3, param4, function(...args) {
myFunction.call(objAsThis, ...args)
});
This will then ignore the this value that the socket.io library passed to the callback and will attach the one you want. You could also use .bind() to do the same thing:
socket.emit("some event", param3, param4, myFunction.bind(objAsThis));
which is just another way of passing a stub function as shown in the prior code solution.
And, if this was in the lexical context, you could also use an arrow function.
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 have a NodeJS application and I want to execute some method for file validations but just one time (this method will validate some files under the node application).
Is there an elegant way to do this? Events?
The NodeJS documentation on modules states that:
Modules are cached after the first time they are loaded.
which you can take advantage of by adding static code to the module. Regardless of how many times the module is loaded, the static code will retain its state(/value).
You can use that state from a method to implement a method that can be called whenever you like -- at the best time during initialization -- but only ever be called once. This is pretty simple:
var called = false;
function checkFiles() {
if (called) return;
// Perform your validation
called = true;
}
module.exports = {
checkFiles: checkFiles
};
Because of the module caching, you can require this file in as many places as you need and it will still only execute once.
To invoke this function, you have a few options:
For a simple application, you can call the function from your main module (or function) and it will be invoked at that time. If the validation should be asynchronous, you can wrap your main method in a function and pass that to the validator as a callback.
//#! /bin/env node
var express = require('express');
var validator = require('./validator');
validator.checkFiles();
var app = express();
var server = app.listen(3000, function () {
...
});
For a more complicated application, you should call this function during your existing initialization routine (again, using callbacks as necessary).
If you have a nice modern promise-based initializer, you could simply add the validator as the first step of the chain.
I have a simple function which routes a HTTP query pattern, queries redis and sends a response. The following is the code
router.get('/getinfo/:teamname', function main(teamname) {
rclient.hgetall(teamname,function(err,obj){
console.log("the response from redis is ",obj)
cache.put(eventname,obj);
console.log("inserting to cache");
this.res.end(obj); // this object is root cause for all problems
});
}
The router object afaik, sends the response using this.res.end(obj) . I guess since I am trying to do this inside my redis client , I am getting error. Is there any other way to send the value as a response ? I thought of using emitter based model where the channel emits the response and listener gets it. but it feels like a round about way to solving this problem. Is there any simpler approach ?
The error may be because, where you're trying to use this, it doesn't have the intended value -- an object with a res property that in turn has an end() method.
That would be because every function in JavaScript has its own this with its own value. And, when nesting functions, using this will return the value for the closest function (i.e. shadowing).
To resolve that, you can save the intended value to a local variable:
router.get('/getinfo/:teamname', function main(teamname) {
var request = this;
rclient.hgetall(teamname,function(err,obj){
// ...
request.res.end(obj);
});
});
Or, bind the anonymous callback so both functions are forced to have the same this value:
router.get('/getinfo/:teamname', function main(teamname) {
rclient.hgetall(teamname, function(err,obj){
// ...
this.res.end(obj);
}.bind(this));
});
I create a http server using http.createServer(onRequest) and want to measure time needed to make a response.
Currently, in my onRequest handler I do:
var start = process.hrtime();
response.on('end', function (){
console.log('time to respond', process.hrtime(start));
});
// call various asynchronous functions and send them 'response' object. One of them eventually does response.end()
I'm worried if this will work fine when a bunch of requests comes instantly, or will asynchronism break it/mix-up times?
You should do somethinng like,
function measureRequestTime (req, res, next) {
var start = process.hrtime();
response.on('end', function () {
// logging the time here..
});
}
// app init
app.use(meastureTime);
The variable will be in the closure scope of your onRequest handler function so it'll work just the way you expect it to (assuming process.hrtime does what you want).