I got a socket.io client in which the onMessage callback should call handleResponse() to process the received data.
I attached the callback like this:
this.socket.on("message", this._socketOnMessage);
The callback is implemented like this:
_socketOnMessage(data) {
this.handleResponse();
}
And this is handleResponse()
handleResponse() {
console.log("handling response");
}
I can call handleResponse() from anywhere and it works fine, but when called trom the socket callback I get this error:
Uncaught (in promise) TypeError: this.handleResponse is not a function
handleResponse() is undefined in the callback but function everywhere else
Why do I get this error and how do I fix it?
Sounds like handleResponse isn't a function of your socket manager. Just call handleResponse() instead of this.handleResponse().
So the solution is simple:
The scope inside the _socketOnMessage function is WebSockets.
Subsequently this refers to the WebSocket object and not my parent Class in which the socket lives.
So to call handleResponse which also is a function of the parent class it has to be called like this:
parentObject.handleResponse()
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.
In my Chrome App I need somehow Chrome to give the the reference to my object 'identity_service' in this variable when the callback is executed, but I don't know how.
This is my constructor:
function Identity(identity_host,identity_port) {
this.identity_host=identity_host;
this.identity_port=identity_port;
this.socket_fd=0;
chrome.sockets.tcp.create({}, this.socket_create_callback);
}
The function socket_create_callback is defined like this:
Identity.prototype.socket_create_callback=function(info) {
console.log('info='+info);
console.log('constructor name:'+this.constructor.name);
console.log('hostname='+this.identity_host);
this.socket_fd=info.socketId;
}
This is how I create it:
var identity_service=new Identity("localhost",4433);
Without object oriented programming Chrome calls the callback function with the parameter 'info' and it works fine. But when using OOP the 'this' variable doesn't hold the reference to my 'Identity' object otherwise the 'hostname' would not be undefined. This is what I get in the console log:
identity.js:21 info=[object Object]
identity.js:22 constructor name:Object
identity.js:23 hostname=undefined
With correct invocation of the callback the name of the csontructor would be 'Identity'. How can this be fixed?
The Chrome API call for creating a socket is this:
create
chrome.sockets.tcp.create( SocketProperties properties, function callback)
Creates a TCP socket.
I have a controller with many functions defined on $scope.
Ex:
$scope.doSomething = function() {
}
$scope.doSomethingElse = function(data) {
}
From my doSomething function, I want to call my doSomethingElse function. Right now, I am calling it in the success function of my HTTP request (yes, it is succeeding).
Once the success function triggers, I'm calling the other function like so:
angular.scope().doSomethingElse(data); The data variable is passed through as a parameter in the success function.
After running, I'm receiving this error: TypeError: undefined is not a function
Is there another way to do this?
You can just call $scope.doSomethingElse(data); since you've already defined it as a function. As long as it is defined before you call it, this will work.
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.