JavaScript variable life time - javascript

I am learning node.js and JavaScript. Following is the code. I found the var http is outside the function start2. I am wondering why it works? Since we only exports function start2, right?
Is this some concept about closure? (I've tried put the var http inside the start2. It works for sure.)
var http = require('http');
function start2(){
function onRequest(request,response){
console.log("Request recieved");
response.writeHead(200,{"Content-Type":"text/html"});
response.write("<h1>Hello world</h1>");
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
exports.start=start2;

You could put var http = require('http'); inside your function but most often that's not how people code it. People place it at the top like you have it. Why? This is a call to the module system to load module http. Most often, you want to do this once and make it available for your entire file. If you are doing to use this module multiple times in your file you don't want to call require again and again.
If a module it is rarely used and perhaps expensive to load, then it may make sense to have the require call inside a function, instead of paying the cost of loading it each and every time:
function calledUnderExceptionalCircumstances() {
var expensive = require('expensive');
expensive.foo();
}

In the code that you have attached, require loads a module into the global scope. Since you have defined function start2 in the same scope, due to closure, var http is available inside function start2.
In the second code snippet you have provided, due to closure, the reference to the variable env_var1 is made available inside f1, which is getting re - assigned.
If at all, instead of directly re - assigning env_var1 if you are redefining env_var1 as var env_var1, var env_var1 becomes a local variable and it's scope is confined within f1 and inside f2, it would print "aaa" instead of "bbb" as you would have expected.
Hope this helps.

Related

wait for an async operation before requiring other modules

In my main.js, I am reading a file asynchronously. Once my file is loaded, I set some objects in GLOBAL namespace and use them in my required modules (using GLOBAL namespace or not is a different story, I am using it anyway).
My required module immediately expects that variable to exist at the time of loading. So how do I make it wait till my file reading is complete in the main.js? Do I simply require module in the callback of readFile? Or there's a better way to do it?
example:
fs.readFile('./file', function (data) {
// do something
GLOBAL.obj = data;
});
require('./module.js');
module.js
obj.someFunction();
Your gut feeling of disliking that solution is understandable. (Your stomach is right). The proper way of cleaning this up (and you should take the time – future-you will thank you for it):
go through every one of your ten modules
for each one go through all the functions it exports
for each function figure out, what globals they actually depend on.
add those as arguments to the function.
if they take a lot of arguments now, consider grouping them into objects, creating useful models.
if a bunch of functions all depend on the same set of variables, you can also consider creating a factory function
create a function that takes the formerly global variables as arguments and wrap all of the module's code into that function.
make that function the single export of your module. It serves as a factory function and creates the context for all the other functions in that module. It should return whatever the module exported before.
Example
// DB used to be a global
module.exports = function(DB) {
function getUser(user, cb) {
DB.get('user', db);
}
return {getUser: getUser};
};
You can then use it like this:
var module = require('module')(DB);
module.getUser(myUser, function(){}};
Yes, just follow the rule #1 of async programming. Stuff that depends on callback happening must be executed in that callback. Since your require depends on the variable set in async, you can only use your require inside it:
fs.readFile('./file', function (data) {
// do something
GLOBAL.obj = data;
require('./module.js');
});

socket.io - emitting from within an anonymous function

I am quite new to the world of async. I am trying to do everything with callbacks at first before using any of the libraries out there. I think I have a closure problem, but don't know what to do about it.
Here is some code:
namespace.on('connection', function(socket){
var newClient = socket.id//just in case the a new user logged on between declaration and use
socket.join('room1')
function newConnection(positionCallback, hashCallback, newUser){
namespace.to(socket.id).emit('hello', {yo:'works'})
for(var i=0; i< cardCounter ;i++){
var keyVal = 'card:'+ cardArray[i]
redis.hgetall(keyVal, function (err, storedMsg) {
namespace.to(socket.id).emit('hello', {yo:'doesnt work'})
hashCallback(storedMsg, newUser)
});
if(i==cardCounter-1){
positionCallback()
}
}
}
function onConnectionComplete(){
namespace.to(socket.id).emit('hello', {yo:'works'})
}
function onHashComplete(hashObject, newUser){
namespace.to(newUser).emit('hello', {yo:'doesnt work'})
}
newConnection(onConnectionComplete, onHashComplete, newClient)
}
I have placed some socketio emits around the place to pinpoint where things go wrong.
Any emits outside of the call to redis work as expected. As soon as I go inside that anonymous function - nada.
That said, I have console.log()'ed everything inside that function. I get the right results from redis, I have the right user, and namespace is defined.
I just can't emit the result.
I would have thought that the anonymous function had access to the scope just outside it - but not the other way around. I don't see what is not making it across...
Also I know that some people don't like the if statement to invoke a callback, but that might be a discussion for another day.
It was a closure problem! Just not what I was expecting.
I also, ahem, don't really understand it.
The callback isn't the problem, getting variables accessible inside the redis response function is. I would have thought that any variables declared in a parent/ancestor function are available to children/decedent functions.
In this instance I needed to create a function inside the loop, and explicitly pass variables for it to be available inside a closure.
Here is the stackoverflow question that pointed me in the right direction:
How can I access the key passed to hgetall when using node_redis?

Updating parameters to JavaScript callback before it returns, without using globals

I'm working on making a modification to a node.js module to improve error handling for one of my uses cases. The specifics of the module aren't really relevant, but one of the things I want to do is trigger a delayed retry when receiving a certain status code from the response to an API request. To do this I'm using the timeOut function to trigger a new call to the function after a period of time.
The structure of the code looks like this:
Outer function (parameters specified by client application)
——API request (using parameters)
——Callback from API request (response with status code)
——If error, set timeout to call outer function after delay
However, I also want to handle the case that the outer function is called again while waiting for the timeout. I don't want any calls to trigger a new API request while a timeout is pending, but I do want the parameters from the most recent call to be used when the timeout finishes.
I've been able to get this working using variables that are global to the module. Each time a new call comes in to the outer function it updates a global object with the new parameters then, if a timeout is pending, returns without calling the API request. The timeout function uses the parameters from the global object to call the outer function, rather than the parameters from when it was set. This way it always uses the most recent values that were passed into the outer function, but doesn't make duplicate API calls.
Here's a simplified example of how I've achieved this behavior with global variables: JSFiddle. Hit run a few times until you get a "failure response" which then triggers the timeout.
This works, but I would prefer not add these global variables into the module if there's a better way.
Is there any way to get this same behavior but have all of the state encapsulated in the outer function without using globals? I'm also open to completely rethinking the way I'm handling this if anyone has ideas.
You're not going to be able to do this without creating variables outside of your outer function, however it's still possible to create those variables without polluting your global scope.
To do so, wrap your outer function in another function that gets executed immediately, sometimes known as an IIFE:
mainFunction: (function() {
var savedParam1;
var savedParam2;
var savedParam3;
var pendingTimeout = false;
return function(param1, param2, param3) {
savedParam1 = param1;
savedParam2 = param2;
savedParam3 = param3;
if (pendingTimeout) {
log('pending timeout -- ignoring new call');
return;
}
/* and so on */
}
})(); // the () causes the outer function to run immediately,
// which creates a scope for the savedParam / pendingTimeout variables,
// and then returns the inner function (your old outer function)
// to be used for mainFunction

How to execute different partsof the JS code in one scope

I have several script blocks depend on each other. I need to perform them in one scope.
My attempt:
var scopeWrapper = {};
with(scopeWrapper) {
(function() {
this.run = function(code) {
eval(code);
};
}).call(scopeWrapper);
}
scopeWrapper.run('function test() { alert("passed"); }');
scopeWrapper.run('test();');
I get 'test is not defined' error. It seems that the code is executed in different scopes.
Why is this happening?
Edit: Bergi pointed out my original answer was wrong, he is correct. Since eval runs in its own scope and the function constructor still runs in function scope according to the spec this is not possible with either.
While I have done this sort of thing myself several times with node.js using the vm module where you get much finer grain of control over where your code executes, it seems browsers require a different approach.
The only way you can share variables in such a way is to do so in the global scope of JavaScript execution (possibly, in an iframe). One way you could do this is script tag injection.
function run(code){
var sc = document.createElement("script");
sc.setAttribute("type","text/javascript");
sc.innerHTML = code;
document.body.appendChild(sc);
}
run("var x = 5");
run("document.write(x)");
(here is this code in action)
As for the scope wrapper, instead of injecting them in the same frame inject them in another iframe. That will scope their window object to that iframe and will allow you to share context.
I humbly apologize for my previous answer, I misread the spec. I hope this answer helps you.
I'm leaving my previous answer here because I still believe it provides some insight into how eval and the Function constructor work.
When running code in non-strict mode eval runs in the current context of your page
After your function declaration is done, the scope it was declared in dies, and with it the function.
Consider using the Function constructor and then .calling it
In your case that would be something like:
var scopeWrapper = {};
scopeWrapper.run = function(code){
var functionToRun = new Function(code);
functionToRun.call(scopeWrapper);
}
scopeWrapper.run('this.test = function() { alert("passed"); }');
scopeWrapper.run("this.test()")
Here is a reference directly from the spec:
If there is no calling context or if the eval code is not being evaluated by a direct call (15.1.2.1.1) to the eval function then,
Initialize the execution context as if it was a global execution context using the eval code as C as described in 10.4.1.1.
If this code is run in the node.js consider using the vm module. Also note that this approach is still not secure in the way it'll allow code you run to change your code.
test only exists in the scope of this.run and only at call time :
// global scope
(function(){
// local scope (equivalent of your "run" function scope)
eval('function f(){};');
console.log(f); // prints "function f(){}"
})();
console.log(f); // prints "ReferenceError: f is not defined"
Each call of run creates a new scope in which each code is evaluated separately.

Persistent variables in nodeJS

I am writing a node app that needs to remember data across connection iterations of the createServer() callback. Is there a simple way that doesn't involve databases or file r/w? I've sofar attempted creating objects in the respective modules and even main script while passing them into various response handlers, however for every connection they are flushed.
What I mean by that:
require('http').createServer(function(req,res){
route(req,res,object);
}).listen(cp=80);
object={variable:0}
function route(req,res,object){
res.end();
console.log(object.variable);
object.variable=Math.floor(Math.random()*100);
}
console.log is unsurprisingly throws 0 every connection in this case. Is there any way to create global variables, not in the sense of being available across modules, but persistent unlike var's?
Each module in Node has its own scope, so no, var Foo; does not create a global variable Foo. Use global object from inside the modules.
UPDATE:
require('http').createServer(function(req,res){
route(req,res,object);
}).listen(cp=8080);
object={variable:0}
global.foo = 'Bar'; // I added this
function route(req,res,object){
res.end();
console.log(object.variable);
console.log("foo = %s", global.foo); // I added this too
object.variable=Math.floor(Math.random()*100);
}
And it logs "foo = Bar" as expected as well.

Categories