How to provide executing function object instance to a callback in Javascript - javascript

I have a namespace object on which I have defined some functions. One of the functions is used to create a websocket session to a remote server.
ns.Session = function(url, config, callback){
var ws = new WebSocket(url);
ws.onmessage = function (e){
if(login(e.data)){
// This is the point at which I need to pass back the session object to callback
callback(session):
}
}
....
}
In Javascript, as far as I know if someone invokes this function using ns.Session(....) then the this object will be ns. So, how do I get the instance of the "session" to send to the callback.
arguments.callee is deprecated as far as I know.
The whole reason I am doing it this way is that the session is not considered "usable" till the server confirms the login, so I don't want to prematurely return the function object before it is actually connected and logged in. Hence the use of a callback. If there is a better way to achieve this, I am open to that too.
Session has a bunch of other inner functions like addHandler, sendData etc which I have not shown here for sake of brevity.

You can use pointer to function like this:
ns.Session = function session(...) {
// 'session' here points to your function, so you do
callback(session); // like you wrote
callback(ns.Session); // same effect if you don't change ns and ns.Session pointers
}
Also, I don't see why you use the word "instance" in this case, because functions have only one instance. If you call it with the 'new' keyword, function creates new object from the function, and now there you can use "instance" word.

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.

Is it unsafe to invoke a function by it's name as a string using the window object?

Would you please tell me if there is anything unsafe, in the JS of a standard web page, about invoking a function by it's name as a string using window['function_name']()? I remember reading something about it quite some time ago but cannot locate it now.
I thought there was a reason to not use the window object to do so, because to invoke functions between a background script and content script in a web extension, I always declare a different object in each and declare the functions that can be invoked in this manner as properties of the object and pass the function names as strings in the communication port to invoke them; but I cannot remember why.
Thank you.
It depends on which context your running the code,
1. JS Execution Context
Its fine to use string as function name and call the corresponding function residing in an object.
const functionName = "someFunction";
window[functionName]()
But If string is part of a untrusted data or user controllable string then it not safe to use. i.e Reading a string from a url parameter.
Example:
const unTrustedUserInput = window.location.hash
window[unTrustedUserInput]();
2. web Extension BG & CS Context
As per chrome recommendation, you should not trust the message received from content-script. You should always sanitise the input and place necessary validation before executing it.
So, I would recommend not to pass function name as string, instead use a dictionary map with corresponding guid to validate to which function the call is made.
Example:
// cs context
chrome.extension.sendMessage({ id: "<GUID-1>", data: "data" }, (response) => {
// handle response if any
});
// BG context
var CSBGCommunicationMap = {
"<GUID>-1": window.someFunction
}
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
if (sender.id !== "<varlidate id-ur-Extension>" && sender. origin !== "<validate origin>") {
// Early return if it comes from malicious content or unknown sender
return;
}
if (message.id && message.id in CSBGCommunicationMap) {
const functionToBeCalled = CSBGCommunicationMap[message.id];
// functionToBeCalled(message, sendResponse);
}
});
I hope this clarifies your concern.
According to MDN, The Window object is a global object which contains the entire DOM document. So if you call a function foo() (without specifying any object), Javascript will search it in window object.
In other hand,
foo() , window.foo() and window['foo']() are same. But when talk about security, Let's say if user injects some malicious code into the function foo,
doesn't matter you invoke the function foo() or window['foo'](), The injection will effect both.
Avoid using Window object
You don't need to specify the window object to call a global scoped functions or variable unless, it shadowed by your current scope.
function x() {
console.log('hey i am global');
}
function y() {
function x() {
console.log('I have power only inside y()');
}
x(); // I have power only inside y()
window.x() // hey i am global
}
And If you don't handle window object properly, There are lot of chances to get run-time errors and the entire object will be collapsed.

Callback within a promise within a class?

I have a class that I use to load external resources via an XMLHttpRequest (this is for WebGL) so I'm loading models, shaders etc. My plan was to put a loading display up whilst it did all these requests and then when it's finally complete I want it to run a callback function from the original function that created it. However, I'm getting strange results when I try to run that call back (such as it has no access of any of the objects within the class that did the loading).
I can get around this problem by passing "this" into the loading class and then doing
self = this;
promise(self.callback());
but I'd much rather specify the function that I want it to callback to after its done the loading. Does anyone know if this can be done? My code looks like this:
Main Class
this.loadingClass = new LoadingClass(this.LoadingComplete, resources);
Main.prototype.LoadingComplete = function()
{
// Returns undefined if i specify the callback function instead of just "this"
console.log(this.loadingClass.anyOfTheMembersOfThisClass);
}
Loading Class
LoadingClass = function(callback, resources) {
..
Promise.all(resources).then(function(loadedResources)
{
..
callback();
});
}
When you pass the function object as
(this.LoadingComplete, resources)
the object to which it was bound, will not be passed. So, only the function object LoadingComplete is passed to LoadingClass and when it is invoked as
callback()
the this value will be undefined (in strict mode).
To fix this,
you need to bind the this object, like this
new LoadingClass(this.LoadingComplete.bind(this), resources)
if your environment supports ES2015's Arrow functions
new LoadingClass(() => this.LoadingComplete(), resources);
In both these cases, when the LoadingComplete is invoked from LoadingClass, the this will be retained.
You are detouching callback (read about "this") function from the root object, so of course it loses context. Specify bindingContext explicitly with Function.prototype.bind method:
this.loadingClass = new LoadingClass(this.LoadingComplete.bind(this), resources);

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

Alternative for Javascript this object

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

Categories