The mechanics of the JavaScript WebSockets API - javascript

I've been trying to understand some code used to open a websocket:
var ws = new WebSocket('ws://my.domain.com');
ws.onopen = function(event) {
...
}
My question is how does the handshaking get started? If it is started in the WebSocket constructor, then how does onopen get called if it isn't set by then? If the WebSocket constructor creates a thread that does the handshaking, then does onopen have to be defined quickly enough before the handshaking is over? If so, that sounds a little dangerous because if the JS virtual machine is slowed the handshaking could be finished before onopen is defined, which means that the event is not handled. Or does setting the onopen function trigger the handshaking?
Could someone explain to me the mechanics of the API please?

It does not look for onopen function until end of execution of current (synchronous) code. That is because the connection (and thus calling onopen callback) is asynchronous.
Consider:
let x = false;
setTimeout(function () {
x = true
}, 1000);
while(!x){
console.log('waiting!');
}
The while loop there will never end but you would probably suspect it'd end after one second.
If you delay the initialisation of onopen function by executing time-consuming (but synchronous) code then it is not dangerous. On the other if you setTimeout initialisation of onopen then there's no guarantee whether it's defined or not at the time the WebSockets connection is ready as you can't be sure which callback will be executed first.
If you were doing the same thing in C++ you'd use threads for that. In JavaScript callbacks mechanism is not thread-based; it just behaves thread-like (see the endless while loop above).
Single thread executes one code-unit at a time and other code units
are queued until the current code unit is finished executing
source: http://www.slideshare.net/clutchski/writing-asynchronous-javascript-101
It's important to understand that even if you setTimeout something for 1s it might not execute after one second - If the thread is busy it might never get executed.
Thus if you initiate WebSocket connection and run a loop similar to the one above but waiting for the connection to be ready it might never end.
This behaviour might look strange for programmers not familiar with JS. Therefore for readability I define callbacks at the same time or immediately after the functions which need them whenever it's possible.
If you want to explicitly use threads and concurrent execution, read more about Web Workers
Reference:
How JavaScript Timers Work
Understanding JavaScript timers

You don't need any setTimeout function. I'm using a library for this and my code looks something like this:
var pushstream = new PushStream({
host: window.location.hostname,
port: window.location.port,
modes: "websocket"
});
pushstream.onmessage = _manageEvent;
function _manageEvent(eventMessage) {
console.log(eventMessage);
}
This gave me a hell of an insight on websockets and how to implement a client in Javascript: https://github.com/wandenberg/nginx-push-stream-module/blob/master/misc/js/pushstream.js
And also the server: https://github.com/wandenberg/nginx-push-stream-module/
It's very well documented I hope it helps :)

Related

NodeJS TCP server not working because of while loop

I'm going to illustrate my issue with this simple example.
What boggles my mind is why the server never gets created
and the socket never gets printed.
If I were to remove the while loop everything works.
What do I have to change to make the example below function?
const net = require('net');
net.createServer(socket => {
socket.setEncoding('utf-8');
console.log(socket);
}).listen(4242, '127.0.0.1');
console.log('do some while logic here')
while(true) { }
This happens because your socket creation is not an instant process. It needs to make system calls and so on. In other words, it is asynchronous. The way javascript works are that it has main loop and callback queue. Basically the main loop is what is executed and callback queue is the things that await to be executed (See MDN docs on this https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop).
What happens in your case is that your callback goes to the callback queue and waits to be executed, but it never gets to do so, because your main loop is blocked by while (true) {} loop. If you want nonblocking behavior you need to send things that are inside you while loop to callback queue instead. One of the ways to do it in javascript is to use setTimeout. E.g.
const net = require('net');
net.createServer(socket => {
socket.setEncoding('utf-8');
console.log(socket);
}).listen(4242, '127.0.0.1');
console.log('do some while logic here')
function main() {
// do something here
setTimeout(main);
}
main()
This way you're not going to have a stack overflow issue and you get nonblocking behavior in you while loop.
Nodejs is an event driven system that runs your Javascript single threaded. That means that in order for things to work properly, you cannot hog the entire CPU in a while() loop (or any other kind of loop) unless the loop directly contains an await statement that is awaiting an actual promise tied to an asynchronous operation.
This is a basic principle of programming in nodejs and you have to learn how to structure your program logic into the event driven world. You don't show what you're really trying to do, but "polling" anything in a tight loop is generally not the correct way to program an event driven system.
So, in the code you show here:
const net = require('net');
net.createServer(socket => {
socket.setEncoding('utf-8');
console.log(socket);
}).listen(4242, '127.0.0.1');
console.log('do some while logic here')
while(true) { }
Your while loop just spins forever and never allows any events to get processed and therefore your server can never get events about incoming connections. The events will just pile up in the event queue, but you never give nodejs a chance to go back to the event queue to process those events. To do so, you must finish what you're doing and return control back to the system (thus why you can't use the while(true) { } loop).
So, you really need to be thinking event-driven programming in nodejs. You set up event listeners and you execute code some time in the future when those events occur. You can artificially create events with setTimeout() or setInterval(), but doing that constantly or with really, really short time durations is just polling and is not an efficient way to program a nodejs server either.
If you show or describe for us what you're really trying to do in the rest of your code, we can advise the most important part of this question which is how to actually write that code in an event-driven fashion.
I repeat, learning how to program in an event-driven fashion is required for an efficient, scalable nodejs server process.

Forever loop while waiting for asynchronous task?

I'm wondering if there's a way to cause JavaScript to wait for some variable-length code execution to finish before continuing using events and loops. Before answering with using timeouts, callbacks or referencing this as a duplicate, hear me out.
I want to expose a large API to a web worker. I want this API to feel 'native' in the sense that you can access each member using a getter which gets the information from the other thread. My initial idea was to compile the API and rebuild the entire object on the worker. While this works (and was a really fun project), it's slow at startup and cannot show changes made to the API without it being sent to the worker again after modification. Observers would solve part of this, and web workers transferrable objects would solve all, but they aren't adopted widely yet.
Since worker round-trip calls happen in a matter of milliseconds, I think stalling the thread for a few milliseconds may be an alright solution. Of course I would think about terminating in cases where calls take too long, but I'm trying to create a proof of concept first.
Let's say I want to expose the api object to the worker. I would define a getter for self.api which would fetch the first layer of properties. Each property would then be another getter and the process would continue until the final object is found.
worker.js
self.addEventListener('message', function(event) {
self.dataRecieved = true;
self.data = event.data; // would actually build new getters here
});
Object.defineProperty(self, 'api', {
get: function() {
self.dataRecieved = false;
self.postMessage('request api first-layer properties');
while(!self.dataRecieved);
return self.data; // whatever properties were received from host
}
});
For experimentation, we'll do a simple round-trip with no data processing:
index.html (only JS part)
var worker = new Worker("worker.js");
worker.onmessage = function() {
worker.postMessage();
};
If onmessage would interrupt the loop, the script should theoretically work. Then the worker could access objects like window.document.body.style on the fly.
My question really boils down to: is there a way to guarantee that an event will interrupt an executing code block?
From my understanding of events in JavaScript, I thought they did interrupt the current thread. Does it not because it's executing a blank statement over and over? What if I generated code to be executed and kept doing that until the data returned?
is there a way to guarantee that an event will interrupt an executing code block
As #slebetman suggests in comments, no, not in Javascript running in a browser's web-worker (with one possible exception that I can think of, see suggestion 3. below).
My suggestions, in decreasing order of preference:
Give up the desire to feel "native" (or maybe "local" might be a better term). Something like the infinite while loop that you suggest also seems to be very much fighting agains the cooperative multitasking environment offered by Javascript, including when thinking about a single web worker.
Communication between workers in Javascript is asynchronous. Perhaps it can fail, take longer than just a few milliseconds. I'm not sure what your use case is, but my feeling is that when the project grows, you might want to use those milliseconds for something else.
You could change your defined property to return a promise, and then the caller would do a .then on the response to retrieve the value, just like any other asynchronous API.
Angular Protractor/Webdriver has an API that uses a control flow to simulate a synchronous environment using promises, by always passing promises about. Taking the code from https://stackoverflow.com/a/22697369/1319998
browser.get(url);
var title = browser.getTitle();
expect(title).toEqual('My Title');
By my understanding, each line above adds a promise to the control flow to execute asynchronously. title isn't actually the title, but a promise that resolves to the title for example. While it looks like synchronous code, the getting and testing all happens asynchronously later.
You could implement something similar in the web worker. However, I do wonder whether it will be worth the effort. There would be a lot of code to do this, and I can't help feeling that the main consequence would be that it would end up harder to write code using this, and not easier, as there would be a lot of hidden behaviour.
The only thing that I know of that can be made synchronous in Javascript, is XMLHttpRequest when setting the async parameter to false https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#Parameters. I wonder if you could come up with some sort of way to request to the server that maintains a connection with the main thread and pass data along that way. I have to say, my instinct is that this is quite an awful idea, and would be much slower than just requesting data from the main thread.
For what I know, there is not something native in JS to do this but it is relatively easy to do something similar. I made one some time ago for myself: https://github.com/xpy/whener/blob/master/whener.js .
You use it like when( condition, callback ) where condition is a function that should return true when your condition is met, and callback is the function that you want to execute at that time.

Javascript internals - clearTimeout just before it fires

Let's say I do this:
var timer = setTimeout(function() {
console.log("will this happen?");
}, 5000);
And then after just less than 5 seconds, another callback (from a network event in NodeJS for example) fires and clears it:
clearTimeout(timer);
Is there any possibility that the callback from the setTimeout call is already in the queue to be executed at this point, and if so will the clearTimeout be in time to stop it?
To clarify, I am talking about a situation where the setTimeout time actually expires and the interpreter starts the process of executing it, but the other callback is currently running so the message is added to the queue. It seems like one of those race condition type things that would be easy to not account for.
Even though Node is single thread, the race condition the question describes is possible.
It can happen because timers are triggered by native code (in lib_uv).
On top of that, Node groups timers with the same timeout value. As a result, if you schedule two timers with the same timeout within the same ms, they will be added to the event queue at once.
But rest assured node internally solves that for you. Quoting code from node 0.12.0:
timer.js > clearTimeout
exports.clearTimeout = function(timer) {
if (timer && (timer[kOnTimeout] || timer._onTimeout)) {
timer[kOnTimeout] = timer._onTimeout = null;
// ...
}
}
On clearing a timeout, Node internally removes the reference to the callback function. So even if the race condition happens, it can do no harm, because those timers will be skipped:
listOnTimeout
if (!first._onTimeout) continue;
Node.js executes in a single thread.
So there cannot be any race conditions and you can reliably cancel the timeout before it triggers.
See also a related discussion (in browsers).
I am talking about a situation where the setTimeout time actually expires and the interpreter starts the process of executing it
Without having looked at Node.js internals, I don't think this is possible. Everything is single-threaded, so the interpreter cannot be "in the process" of doing anything while your code is running.
Your code has to return control before the timeout can be triggered. If you put an infinite loop in your code, the whole system hangs. This is all "cooperative multitasking".
This behavior is defined in the HTML Standard, the fired task starts with:
If the entry for handle in the list of active timers has been cleared, then abort these steps.
Therefore even if the task has been queued already, it'll be aborted.
Whether this applies to Node.js, however, is debatable, as the documentation just states:
The timer functions within Node.js implement a similar API as the timers API provided by Web Browsers but use a different internal implementation that is built around the Node.js Event Loop.

Node JS premature program end

I call a function that stacks two async calls and calls a callback when they have both completed. I am using a really simple method to keep track of the calls that have not completed lock++lock--The problem is that the program exits before the operation of the two functions is complete. I noticed this was the problem when I was debugging and gave the process time to complete before it exits. How can I fix this? (At the moment I am at a bit of a loss on how to exactly explain my problem please ask me anything you need to so I can clarify the question)
-----EDIT
With the script below why when I run it does it just exit? I thought that by calling on I was registering to the event que and the script should continue to run?
var events = require('events');
var eventEmitter = new events.EventEmitter();
eventEmitter.on('spo',function(){
console.log('spo');
});
The problem is that you setup an event emitter and attach a handler to the "spo" event and then you do nothing else. So the node runtime sees that there is nothing left to do and exits. Try this:
eventEmitter.on('spo', function() {
console.log('OK: got event "spo"');
});
eventEmitter.emit('spo');
COMING From a Git Hub thread.
What keeps the event loop alive is handles (sockets, timers, etc.) of which your script has none.
EventEmitter instances are synchronous - that is, they run immediately
- so in your example, once the event has fired, the script is done.
Think of it like this: an EventEmitter in itself isn't useful, it only
becomes useful when it's tied to something that emits interesting
events (data from the network or the file system, a timer that
expires, etc.).
I think that what they are saying is that it is the handle outside of Node into C land that holds the script open.

Is there a general mechanism to timeout events in node.js?

I am learning node.js and most of examples I can find are dealing with simple examples. I am more interested in building real-world complicated systems and estimating how well event based model of node.js can handle all the use cases of a real application.
One of the common patterns that I want to apply is let blocking execution to time-out if it does not occur within certain timeout time. For example if it takes more than 30 seconds to execute a database query, it might be too much for certain application. Or if it takes more than 10 seconds to read a file.
For me the ideal program flow with timeouts would be similar to the program flow with exceptions. If an event does not occur within certain predefined timeout limit, then the event listener would be cleared from the event loop and a timeout event would be generated instead. This timeout event would have an alternate listener. If the event is handled normally, then both the timeout listener and event listener are cleared from the event loop.
Is there a general mechanism for timeout handling and cleaning up timed out processes? I know some types such as socket have timeout parameter but it is not a general mechanism that applies to all events.
There is nothing like this at the moment (that i know of, but i don't know everything).
The only thing i can think of is that you reset it yourself somehow. I've given an example below but I think it may have some scope issues. Should be solvable though.
var to
function cb() {
clearTimeout(to)
// do stuff
}
function cbcb() {
cb()
}
function cancel() {
cb = function() {} // notice empty
}
fs.doSomethingAsync(file, cbcb)
to = setTimeout(cancel, 10000)

Categories