Javascript: Properly Globalizing a Websocket Send Function - javascript

I am working with a WebSocket and trying to be able to send socket data at anytime from throughout my application. When I attempt to access the send command from within another function, I am receiving:
Uncaught InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable.
This only is occuring when I call a function, this is how I am setting up my websocket:
Main.socket = (function() {
var socket = new WebSocket("ws://server:port");
socket.onopen = function() {
console.log("Socket has been opened!");
}
function send() {
socket.send('test');
}
return {
socket: socket,
send: send
}
})();
I am able to call the function globally, and also when I console.log Main.socket from within a function it is able to see the socket. But when I call the send function I get that error.

Here is an alternative solution to waiting for the web socket connection to come online, replace your call to :
function send() {
web_socket.send('test');
}
with this :
function send(msg) {
wait_for_socket_connection(socket, function() {
socket.send(msg);
});
};
function wait_for_socket_connection(socket, callback){
setTimeout(
function(){
if (socket.readyState === 1) {
if(callback !== undefined){
callback();
}
return;
} else {
console.log("... waiting for web socket connection to come online");
wait_for_socket_connection(socket,callback);
}
}, 5);
};

The problem is that the socket has not been opened yet. WebSocket.send cannot be used until the asynchronous onopen event occurs.
While using setTimeout (for a long enough duration) "should work", the correct way to deal with asynchronous JavaScript programming is to treat program flow as a sequence of dependent events.
In any case, here is a small example showing how to use a jQuery Deferred Object which (as of jQuery 1.8 isn't broken and honors the Promises/A contract):
Main.socket = (function($) {
var socket = new WebSocket("ws://server:port");
// Promise will be called with one argument, the "send" function for this
// socket.
var readyPromise = $.Deferred();
socket.onopen = function() {
console.log("Socket has been opened!");
readyPromise.resolve(socket.send)
}
return readyPromise;
})(jQuery);
Then later, in the code that uses this little module:
Main.socket.then(function (send) {
// This will only be called after `Promise.resolve` is called in the module
// which will be called in the `WebSocket.onopen` callback.
send("Hello world!");
})
// This code may or may not execute before the `then` function above
// depending upon the state the Promise/Deferred Object.
// However, we can get consistent program flow by using `then`-chaining
// of promises.
Of course you don't have to use Promises - callbacks will work just fine, although I prefer the unified contract/framework of Promises - and you can use whatever names or structure is most fitting.
Also, note that it might not be good to have a single WebSocket for the entire page lifecycle as this won't correctly handle disconnect and recovery scenarios.

Related

AngularJS API call inside getter function

I've inherited a project in AngularJS with some structural issues. It uses an API call to fetch some settings from an endpoint but sometimes the application attempts to use these settings before they're loaded resulting in an 'undefined' error.
I attempted to solve this by using a getter. The idea was that when some method accesses the settings object, it would check if they were already loaded in and if not, fetch them from the API.
I've got it working after a while but there's a problem with this idea. When multiple methods access the settings at the same time (when loading the page) the API is being called multiple times because the first call hasn't come back to override the internal _settings yet.
vm._settings = null;
Object.defineProperty(vm,'settings',{get: function(){
if(vm._settings == null){
settings_service.get().$promise.then(function success(response) {
vm._settings = response;
console.log(vm._settings);
console.log("returning in");
return vm._settings;
}, function error(err) {
handle_api_error(ngNotify, err);
});
}
else return vm._settings;
}});
I can't figure out a way to let the other attempts to execute the getter wait until the first call returns and use that result instead. I'm not sure if I should use await, promises or something else. Thanks in advance
You want to debounce these requests. You could use an existing library or just implement your own.
app.factory('debounce', function($timeout) {
return function(callback, interval) {
var timeout = null;
return function() {
$timeout.cancel(timeout);
timeout = $timeout(function () {
callback.apply(this, args);
}, interval);
};
};
});

How to get the callback from a socket.io emit and then return it to the parent function

I have a js function called listClients. It makes a socket.io emit request to grab a list of clients from a node.js server which uses fs to read a file and then send the data back to the client through a callback.
I need to return the callback data to the original function so clients can execute the function and use the data which it returns, but it's not working due to the callback being wrapped in it's own function. What's the best way to work around this?
Client:
function listClients() {
var sender = getCookieData('relay_client_id');
if (sender) {
socket.emit('list_relay_clients', sender, (callback) => {
return callback; //This won't work because it's async
});
return callback; //<---- I need it to be here
}
}
Server:
socket.on('list_relay_clients', function (sender, callback) {
callback(fetchAllClients());
});
This is more of a basic JS and async execution problem. You have a Async call and your want to return a synchronous output. This is not the right thing to do though. So you should start looking at promises in this case
function listClients() {
return new Promise( resolve => {
var sender = getCookieData('relay_client_id');
if (sender) {
socket.emit('list_relay_clients', sender, (callback) => {
resolve(callback)
});
}
});
}
Then the users of the function should call this function in below way
listClients().then(data=>console.log(data))
If they are not interested in waiting like this and they have async/await JS functionality available then they can use
async function clientCode() {
let clientData = await listClients();
}
If you still further like to make it synchronous read the below article
http://www.tivix.com/blog/making-promises-in-a-synchronous-manner
But since JS is async, a operation which involves a network call, you should try to keep it async, trying to make it a sync one is not a good practice

Node.js async, but only handle first positive/defined result

What is the best way to create parallel asynchronous HTTP requests and take the first result that comes back positive? I am familiar with the async library for JavaScript and would happy to use that but am not sure if it has exactly what I want.
Background - I have a Redis store that serves as state for a server. There is an API we can call to get some data that takes much longer than reaching the Redis store.
In most cases the data will already be in the Redis store, but in some cases it won't be there yet and we need to retrieve it from the API.
The simple thing to do would be to query Redis, and if the value is not in Redis then go to the API afterwards. However, we'll needlessly lose 20-50ms if the data is not yet in our Redis cache and we have to go to the API after failing to find the data with Redis. Since this particular API server is not under great load, it won't really hurt to go to the API simultaneously/in parallel, even if we don't absolutely need the returned value.
//pseudocode below
async.minimum([
function apiRequest(cb){
request(opts,function(err,response,body){
cb(err,body.result.hit);
}
},
function redisRequest(cb){
client.get("some_key", function(err, reply) {
cb(err,reply.result.hit);
});
}],
function minimumCompleted(err,result){
// this mimimumCompleted final callback function will be only fired once,
// and would be fired by one of the above functions -
// whichever one *first* returned a defined value for result.hit
});
is there a way to get what I am looking for with the async library or perhaps promises, or should I implement something myself?
Use Promise.any([ap, bp]).
The following is a possible way to do it without promises. It is untested but should meet the requirements.
To meet requirement of returning the first success and not just the first completion, I keep a count of the number of completions expected so that if an error occurs it can be ignored it unless it is the last error.
function asyncMinimum(a, cb) {
var triggered = false;
var completions = a.length;
function callback(err, data) {
completions--;
if (err && completions !== 0) return;
if (triggered) return;
triggered = true;
return cb(err, data);
}
a.map(function (f) { return f(callback); });
}
asyncMinimum([
function apiRequest(cb){
request(opts,function(err,response,body){
cb(err,body.result.hit);
}
},
function redisRequest(cb){
client.get("some_key", function(err, reply) {
cb(err,reply.result.hit);
});
}],
function minimumCompleted(err,result){
// this mimimumCompleted final callback function will be only fired once,
// and would be fired by one of the above functions -
// whichever one had a value for body.result.hit that was defined
});
The async.js library (and even promises) keep track of the number of asynchronous operations pending by using a counter. You can see a simple implementation of the idea in an answer to this related question: Coordinating parallel execution in node.js
We can use the same concept to implement the minimum function you want. Only, instead of waiting for the counter to count all responses before triggering a final callback, we deliberately trigger the final callback on the first response and ignore all other responses:
// IMHO, "first" is a better name than "minimum":
function first (async_functions, callback) {
var called_back = false;
var cb = function () {
if (!called_back) {
called_back = true; // block all other responses
callback.apply(null,arguments)
}
}
for (var i=0;i<async_functions.length;i++) {
async_functions[i](cb);
}
}
Using it would be as simple as:
first([apiRequest,redisRequest],function(err,result){
// ...
});
Here's an approach using promises. It takes a little extra custom code because of the non-standard result you're looking for. You aren't just looking for the first one to not return an error, but you're looking for the first one that has a specific type of result so that takes a custom result checker function. And, if none get a result, then we need to communicate that back to the caller by rejecting the promise too. Here's the code:
function firstHit() {
return new Promise(function(resolve, reject) {
var missCntr = 0, missQty = 2;
function checkResult(err, val) {
if (err || !val) {
// see if all requests failed
++missCntr;
if (missCntr === missQty) {
reject();
}
} else {
resolve(val);
}
}
request(opts,function(err, response, body){
checkResult(err, body.result.hit);
}
client.get("some_key", function(err, reply) {
checkResult(err, reply.result.hit);
});
});
}
firstHit().then(function(hit) {
// one of them succeeded here
}, function() {
// neither succeeded here
});
The first promise to call resolve() will trigger the .then() handler. If both fail to get a hit, then it will reject the promise.

Most idiomatic way to code an object who's successful construction depends on an http call in Nodejs

I am new to node and I'm currently wrestling with finding the most iodomatic way to create an object whose construction depends on the results of an http query. The object is useless until the query is returned and parsed successfully so it feels wrong to return from the constructor without my object being initialized but everything I've read about node says I should keep things asynchronous.
I could either write it synchronously like this (pardon the pseudocode)
function FooConfig(cfg_url) {
// use httpsync to get the response synchronously
var response = get(cfg_url);
if (response.is_good()) {
// parse response and set member data from response
this.bar = response.bar
} else {
// Raise an error
}
};
or asynchronously
function FooConfig(cfg_url) {
// Use the regular http module and make the request asynchronously
var newCfg = this;
http.get(cfg_url, function(response) {
if (response.is_good()) {
newCfg.bar = respsonse.bar
} else {
// Raise an error
}
});
});
The problem with the async version is that any client code that depends on an instance of FooCfg might fail if the request is not completed.
i.e.
var myCfg = new FooCfg('www.someurl.com/config')
// request is still pending
var myDependentObject = new DependsOnConfig(cfg); // Error, this neeeds myCfg.bar
Is this an instance where its ok to be synchronous? this should only happen once when the node application is being initialized.
I would use a Factory for this. Basically, instead of doing your async fetch inside your constructor, do it in a factory method and pass the results of your fetch to the constructor instead. Then, pass back the new object via a callback.
So, your constructor might look something like this:
function FooConfig(cfg_data) {
this.bar = cfg_data.bar
}
And your factory method would look something like:
var fooFactory(callback) {
http.get(cfg_url, function(response) {
if (response.is_good()) {
callback(null, new FooConfig(response)) // Here's the actual constructor call
} else {
callback(new Error("something bad happened"))
}
});
}
You'd call it like:
fooFactory(function(err, myCfg) {
if (err) {
// handle error
} else {
var myDependentObject = new DependsOnConfig(myCfg);
}
});
I would split construction and initialisation into two different parts, and have the initialisation method return a promise, or at least a callback. when the initialisation is done, then use it.

Is there a pattern to manage javascript sync and async call

I have a javascript app saving all data on server, then use REST API communicate server and client.
They works fine, until we start have more and more nested async call or nested sync call which hiding async call. For example:
function asyncFoo(callback) {
callback();
}
function syncCallHidingAsyncCall(){
syncStuff();
asyncFoo(function(){
syncFoo()
});
}
function nestedAsyncCall(callback){
asyncFoo(function(){
anotherAsyncCall(callback);
})
}
// this make refactor code become so hard.
// if we want add step2() after nestedAsyncCall();
// instead of add one line of code
// we need first add callback param in every asyncCall, then pass step2 as a callback
And some unnecessary async call:
// we actually only verify this once.
function isLogin(callback){
if (!App._user) {
ServerApi.getCurUser(function(data){
App._user = data.user;
callback(App._user)
});
}
callback(App._user)
}
function syncCallNeedVerfifyLogin(callback){
// user only need login once, so in most case this is really only a sync call.
// but now I have to involve a unnecessary callback to get the return value
isLogin(function(){
callback(syncStuff())
})
}
So after the project become bigger and bigger, we start forgot their relationship, which one need wait, which one will do magic. And more and more function become async only because some very small thing need be verify on server.
So I start feel their must be some design problem in this project. I am looking for the best practice or design patter, or some rules need follow in this kind heavy communicate app.
Thanks for help.
They exist in several patterns to manage asynchronous data exchange and routine execution. They are called in different names as well:
Promises
EventEmitters
Deferred Objects/Deferreds
Control Flow Libraries
Futures
Callback aggregators
Observer / Publisher-Subscriber
A common implementation is jQuery's Deferred Objects which is also used in managing it's AJAX methods. In NodeJS, there is also AsyncJS and the native EventEmitter. There's even a 20-liner library made by some guy that implements EventEmitter which you could use.
As Bergi says in the comments, the pattern you're looking for is called deferred / promises. There's an implementation built into jQuery. From the docs:
a chainable utility object created by calling the jQuery.Deferred()
method. It can register multiple callbacks into callback queues,
invoke callback queues, and relay the success or failure state of any
synchronous or asynchronous function.
There are a variety of other implementations some of which are outlined in this stackoverflow question.
Make yourself a queue system, something like:
function Queue() {
this.queue = [];
}
Queue.prototype.i = -1;
Queue.prototype.add = function(fn) {
if (typeof fn !== "function")
throw new TypeError("Invalid argument");
this.queue.push(fn);
}
Queue.prototype.next = function() {
this.i++;
if (this.i < this.queue.length) {
this.queue[this.i].appy(this, arguments);
}
}
Queue.prototype.start = function() {
if (this.i !== -1)
throw new Error("Already running")
this.next.apply(this, arguments);
}
And use it like this:
var q = new Queue();
q.add(function() {
// do something async
// In the callback, call `this.next()`, passing
// any relevant arguments
})
q.add(function() {
// do something async
// In the callback, call `this.next()`, passing
// any relevant arguments
})
q.add(function() {
// do something async
// In the callback, call `this.next()`, passing
// any relevant arguments
})
q.start();
DEMO: http://jsfiddle.net/4n3kH/

Categories

Resources