Persistent variables in nodeJS - javascript

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.

Related

How is the value of 'this' different in concrete implementation than on playground?

I am developing an app using a Node-Express stack using Socket.io and I found something weird. I have the following in one of my files:
const server = require('./server')
const io = require('socket.io').listen(server)
const Game = require('./service/game')
const game = new Game()
io.on('connection', (socket) => {
...
game.addPlayer(socket)
socket.on('increaseTime', game.increaseTime) // I know this is wrong
})
I have read about how you have to bind this if you want to use a callback as a handler, so in this specific case I know that on the commented line one of the solutions is the following to actually bind 'this' to the game instance, instead of the socket:
socket.on('increaseTime', game.increaseTime.bind(game))
What I do not understand is not this issue, but related to this. If I leave the line as is, so in the 'wrong' version I would still like to know how is the value of 'this' the socket. That is not what I would expect, because if I try to simulate this in a playground file, the value of this would be the the global object:
const socket = {
on(label, callback) {
callback()
},
}
const game = {
increaseTime() {
console.log(this)
}
}
socket.on('increaseTime', game.increaseTime) // global object
My guess is that the reason that it is the global object is that the value of this is lost, because when we use the 'this' keyword in a function inside of another function, it loses it's value and falls back to the global object (https://spin.atomicobject.com/2014/10/20/javascript-scope-closures/). My main question is how is it possible that the value of 'this' is the socket if I leave the 'wrong' implementation, how is it not the same as in the playground file?
I also tried instantiating dummy classes to have something resembling the actual implementation, but then the value of 'this' would be undefined, which I do not understand either (maybe it could be that the class keyword uses strict mode implicitely, so the fallback is not the global object, I don't know).
Any help would be greatly appreciated!
The value of this depends on how the function is called.
game.increaseTime.bind(game) creates a function which calls increaseTime with game as the this value.
callback() calls the function passed to the callback argument (and copied from game) without any explicit context (so this is the global object).
The code underlying socket.on clearly calls the function passed to it with the socket as the this value. There are several ways it could do that, you'd need to look at its source code to determine which one it uses.

Why I can't access global variable from javascript function in jasmine

I'm using Jasmine standalone https://github.com/jasmine/jasmine/releases
I have declared a global variable global_song in SpecRunner.html (I can access it from chrome console so it's truly global) which includes script where I am trying to concatenate global_song to "should be able to play Song " :
it("should be able to play Song " + global_song, function() {
player.play(song);
expect(player.currentlyPlayingSong).toEqual(global_song);
//demonstrates use of custom matcher
expect(player).toBePlaying(song);
});
Why it cannot access global_song variable ?
Update : expect(player.currentlyPlayingSong).toEqual(global_song) works whereas it("should be able to play Song " + global_song doesn't work.
Where have you defined global_song? If you did that in the beforeEach() function this behaviour would make sense as the code in the describe block (which attempts to define your it() function) gets executed before the beforeEach() as described in this other SO answer.
Well i suppose your global_song created after executing of
player.play(song);
That's way it's not available in test as first parameter of it and available after executing player.play in expect(player.currentlyPlayingSong).toEqual(global_song) assertion.
Try to add simple assignment to global_song separatelly from player.play to verify that it's available before player.play executed:
window.global_song = 'value'
Just take a look on that sample to illustrate the main possible candidate of problem:
function foo(){
window['bar'] = 'bar';
}
console.log(window.bar); // Undefined
foo(); // now window contain bar variable.
console.log(window.bar); // 'bar'

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');
});

JavaScript sandboxing: hide global variables from a given scope

I want to create an HTML+JS environment where user can enter and run arbitrary JavaScript code which will be executed in context of given jail object. I've set up a playground to illustrate what I have so far.
This one does a somewhat decent job:
Basic evaluation works:
Input: 2 + 2
Output: 4
this returns jail object
Input: this
Output: [object Object]
this.hello() runs expected method
Input: this.hello()
Output: hello world!
User can set up their own functions and execute them later:
Input: this.foo = function() { return 42; }
Output: function () { return 42; }
Input: this.foo()
Ouput: 42
Trying to access some object that I want to stay "hidden" from jail context fails:
Input: hidden
Output: ReferenceError: hidden is not defined
However, it completely fails to hide globally accessible properties, such as window or document for user:
Input: window
Current output: [object Window]
Desired output: ReferenceError: window is not defined
The best solution I've came up so far is to just fill up all the global variable I can think of with undefined or null right in the Jail object declaration, as illustrated in updated version. This way they seem to be lost forever inside the scope of jail and user won't be able to access them. My questions:
Am I right? Is this safe enough?
Is there any better way, i.e. to really undefine global stuff in certain scope instead of rewriting them with some placeholder values?
If it’s client-side and you can guarantee a modern browser, use web workers instead; they’re much safer, and you can also stop infinite loops from tying up the main thread, and implement timeouts by calling Worker#terminate.
Start up a new worker for each execution:
var worker = new Worker('path/to/evaluator.js');
Receive messages from the worker:
worker.onmessage = function (e) {
console.log(e.data);
};
Send over the code to execute:
worker.postMessage(someCode);
In the worker, listen:
onmessage = function (e) {
postMessage(eval(e.data));
};
And make sure to call terminate after receiving the message, too, because the worker can call postMessage itself. (You can prevent that, but there’s really no point.)
Web workers don’t have access to anything in the main execution context, they run on another thread, and they’re implemented by the browser, so they’re much safer than the typical delete-dangerous-things sandbox.
They do, however, have access to XMLHttpRequest; see Is It Possible to Sandbox JavaScript Running In the Browser? for other approaches if this is a problem.

JavaScript variable life time

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.

Categories