I'm working on a javascript client in angular that uses SignalR to communicate with a backend server. The basic idea is that you can do remote procedure calls on the server from the client and vice versa. I have an appropriate abstraction for calling a server method that takes no parameters as follows:
myInvoke: function (methodName, callback) {
proxy.invoke(methodName)
.done(function (result) {
$rootScope.$apply(function () {
if (callback) {
callback(result);
}
});
});
}
The important part being proxy.invoke(methodName) which takes the name of the server method to call as a string.
proxy also allows passing multiple arguments to invoke. Some examples from SignalR documentation:
// one parameter
contosoChatHubProxy.invoke('newContosoChatMessage', { UserName: userName, Message: message}) ...
// two parameters
contosoChatHubProxy.invoke('NewContosoChatMessage', userName, message) ...
What I'd like to accomplish is something more like this where args is any number of arguments that should be forwarded on to the hub:
myInvoke: function (methodName, args, callback) {
proxy.invoke(methodName, args)...
I've been reading about the apply method but my javascript is pretty weak and I haven't been able to come up with a working implementation.
Ignore my previous comment. I misread the SignalR doc you included. Basically I was assuming you could always pass a single object parameter. It does look like you can accomplish what you want by doing
See this jsbin for how to use apply to pass the arguments from the current function to the invoke function.
http://jsbin.com/juqanigulo/1/edit?html,js,console,output
Related
I'm making a Chrome app that involves connecting to several BLE peripherals and sending write messages simultaneously to them. I need to know when each write operation has finished on which peripheral so I can initiate more operations for that peripheral, but there doesn't seem to be a way to reference the peripheral from the callback function. The callback function is passed as a parameter to the Bluetooth API write function:
chrome.bluetoothLowEnergy.writeCharacteristicValue(string characteristicId, ArrayBuffer value, function callback)
The API shows that the READ callback function has a characteristic parameter:
function(Characteristic result) {...};
And I've then been using result.service.deviceAddress to find which device the callback is for. But the WRITE callback does not have parameters.
This gives me no way to reference the peripheral that was written to, so I can't figure out which peripheral caused this write callback to run. I can see you could do this by having a unique callback function for each of a fixed number of devices, but could someone elaborate on how to do this more dynamically using a single callback function?
I ended up adding a shared function for the callbacks (d is a Device instance):
var writeCallback = function (d) {
//...
}
Then, in my object that keeps track of the device, I added a property for a call to this function using this:
class Device {
constructor(device) {
//...
this.writeCallbackLink = (function () {
writeCallback(this);
}).bind(this);
}
}
The bind(this) is vital to make sure that this refers to the actual object and not the runtime context. Then, when I call the API function, I use the callback link:
chrome.bluetoothLowEnergy.writeCharacteristicValue(d.write.instanceId,
data_buffer, d.writeCallbackLink);
This causes writeCallback to run with the d that triggered it as a parameter.
Coming from the Java Programming Language where all information that can be used in a method must either be part of a class, or passed by parameter, I'm very confused on to where JavaScript magically generates it's very important data.
In this case I'm using Socket.IO and trying to call a login-method after connection, now I could just use an anonymous function, but I personally believe they're really ugly.
Here's my code:
socketIO.sockets.on('connection', function(socket) {
console.log("Connection maid.");
socket.on('login', login);
});
function login(json) {
sqlConnection.query('select * FROM Accounts', function(err, rows, fields) {
if(err) throw err;
for(var row in rows) {
if(rows[row].Username == json.username) {
console.log("Exists");
socket.emit('login', {nuel: ''});
}
}
});
}
As you can see the login function is called whenever the socket receives a login message, and the json object is magically passed to it. I have no idea where it comes from or what generates it, nor do I have a clue how to pass additional arguments to the method, because it breaks/overwrites the magic data.
The error I'm running into is where socket doesn't exist in the current context, because it was not passed to the login function, however when I try to pass it, the object saved as json is completely eradicated from existence.... AND WHERE IS THE DATA THAT'S HERE COMING FROM.
I don't understand this at all, How can I pass this information to call the method, without completely breaking everything.
I'm very new to Node.js and I'm just trying to make sense of how the parameters work in the callback methods of the code.
I can only understand the first one, function(req,res), because I've used that in Java when working server-side, but I don't really understand how it automatically calls the memcached function or how that kicks off the rest, etc. If somebody could explain to me how this works I'd really appreciate it. Thank you
server.on('request', function(req, res) {
//get session information from memcached
memcached.getSession(req, function(session) {
//get information from db
db.get(session.user, function(userData) {
//some other web service call
ws.get(req, function(wsData) {
//render page
page = pageRender(req, session, userData, wsData);
//output the response
res.write(page);
});
});
});
});
It could roughly be compared to passing the anonymous class in Java. For example to sort a collection in Java you pass a comparator class which has a method for comparing two objects. Later, when sorting algorithms needs to compare the objects it calls the function in provided class.
In javascript functions are first class objects, which means we don't need a "wrapper" class and can pass it as a parameter to another function.
In your case "memcached.getSession" will execute is't logic, find the session, and calls the anonymous function you pass in the second parameter, with the session as parameter.
I'm trying to build an API in JS that will perform some operations and then execute the callback that's registered in AS when it's done. Because it's an API, I am just providing a JS method signature for another developer to call in Flash. Thus, the callback name that's registered in the AS part of the code should be a parameter that's passed in to the JS API in order for JS to communicate back to Flash.
For example:
[AS3 code]
ExternalInterface.addCallback("flashCallbackName", processRequest);
ExternalInterface.call("namespace.jsFnToCall", flashCallbackName);
function processRequest(data:String):void
{
//do stuff
}
[JS code]
var namespace =
{
jsFnToCall: function(callback)
{
//Do stuff in this function and then fire the callback when done.
//getFlashMovie is just a util function that grabs the
//Flash element via the DOM; assume "flash_id"'s a global var
//Below does not work...it's what I'd be ideally be doing some how.
getFlashMovie(flash_id).callback(data);
}
};
Because the definition of the function is in AS, I can't use the window[function name] approach. The only way I can think of is to build the callback in a string and then use the eval() to execute it.
Suggestions? T.I.A.
Well, I can think of one thing I would try, and one thing that would work.
What I would try first.
getFlashMovie(flash_id)['callback'](data);
What would work: Have the callback always be the same, say callback. The first parameter to the callback could be used to determine what actual function to call in flash. For example:
function callback($fn:String, $data:*) {
// either
this[$fn]($data);
// or
switch ($fn) {
case "callback1":
DoSomeCallback($data);
break;
}
Additionally passing the objectID makes it a bit simpler:
ExternalInterface.addCallback("flashCallbackName", processRequest);
ExternalInterface.call("namespace.jsFnToCall", ExternalInterface.objectID, "flashCallbackName");
Then in your JS:
var namespace =
{
jsFnToCall: function(objectID, callback)
{
//Do stuff in this function and then fire the callback when done.
document[objectID][callback](data);
}
};
I have a function which has a jQuery.post being done, with POST parameters passed to it.
function executeFunction(){
jQuery.post("../somefile.php", {executeFunction:true});
}
If I'm not wrong, this is async behavior.
Elsewhere in the code, I have:
executeFunction(function(){
jQuery('#box').reload();
});
After the async behavior is done, I need to take the action of jQuery('#box').reload();
How do I put a check to see if the async behavior has been accomplished?
This third argument to $.post() is the callback function, it runs when your data comes back, like this:
function executeFunction(callback) {
jQuery.post("../somefile.php", {executeFunction:true}, callback);
}
In the above example the pair executeFunction=true is being passed to the server, if that wasn't your intent and you just want to post no data, it looks like this:
function executeFunction(callback) {
jQuery.post("../somefile.php", callback);
}
Also, that callback receives a few parameters if you need to use them, the data (server response), the status, and the XmlHttpRequest, so you can do this for example:
executeFunction(function(data) {
//use data, it's what the server sent back
jQuery('#box').reload();
});