javascript COMET request onunload - javascript

I've recently taken over a project that uses COMET to perform some collaborative work and handle a simple chat room. The guys who originally wrote this thing made up some classes on top of STOMP and Oribited to handle all the actual chatting and messaging and logging.
The problem is that if a user closes the window or navigates to a different page or terminates the connection for whatever other reason, it takes a while for all the other users to see that he has logged off. The other users have to wait for the timestamp of the exited-user's last ping to exceed a certain duration before it registers that the user is no longer connected to the system.
The solution that I can think of requires sending out a notification in the onuload event that the user has left, so that it would notify all the other users without having to wait for a timeout. The problem with this is that since onunload will immediately terminate the connection before it's completed. From what I understand this is a problem with AJAX as well.
Now, I also have read that a Synchronous request in unload will delay the window-close/navigation until the request has finished.
So, my questions is this: does anyone know of a way to temporarily make the comet request synchronous in selected instances so it has time to finish the request before terminating? Or is there another way to solve this problem that I'm not thinking of? Thanks for your help.
Oh, also, onbeforeunload won't work because if it sends the request and the user selects "No, I want to stay on this page" it will have already have notified the other users that he has exited the chat.
tl;dr: Need a way to successfully fire a COMET request in the Unload event. We're using STOMP and Orbited for the COMET stuff.

The 'onbeforeunload' function produces a yes-no dialog only if some value is returned from it. So what you have to do is to use a SYNCHRONOUS XMLHttpRequest (AJAX) request inside the onbeforeunload function without returning anything. And you have to set the asynchronous flag of the request to false as seen in the AJAX GET request shown below:-
AJAXObject.open("GET", 'http://yourdomain/logout?somevar=something', false);
AJAXObject.send(null);
It will prevent the browser from closing until request completes and as I remember, Opera doesn't support 'onbeforeunload', so it won't work for Opera. But it works fine on IE,FF,Chrome.

If you are using comet, then you should control the server. The idea with comet is that it is not constant polling of the server. Every client should have a constant open connection to the server. As such, when the connection closes, the server should be able to send out a notification to the other clients.

Related

How to wait while the server doesn't respond?

I'm building a webpage with some interactions between users and I'm a bit lost.
Any guidance is welcome.
Imagine the following scenario:
Client A opens a 'public' webpage and pressess a button.
Client A starts waiting for the response of client B
Client B goes to an 'admin' webpage and presses a button.
Client A receives the information that client B had pressed a button.
The overall idea to have a page were client A can click a button "I'm ready to play" and starts waiting for client B's response. Client B receives a notification and presses a button "I'm ready too". Client A receives a notification telling Client B is ready too.
I know this could be done with AJAX. But I'm not really sure how to 'wait' for the client B response and update the webpage when the response arrive.
Any help / tip is welcome.
Thanks for your support.
Asynchronous
You seem to think in synchronous way, but that's not how you should think about this. You are issuing a command to the server, but you should not wait for the response, because:
the command might never arrive, for ex. due to Internet connectivity issues
the server might be down
the server might error out your command and never respond
the other player might never receive the message
the other player might never answer the message
the server might never receive the other player's command
the server might error out the other player's command
the server might never send you the notification
you might never receive the notification
So many point of possible failure on the one hand. And... Javascript is single-threaded on the other hand. So, if you wait for the other player to respond, then your UI will froze in the meantime (with the exception of Web Workers, but that's a more advanced topic, for now, let's view Javascript as a single-threaded environment)
Instead you should think asynchronously. In fact, in the achronim of AJAX, the first "A" stands for "Asynchronous". This means that you issue a request and define what you will do when a response is received. This "what will you do" is called the callback. Your client-side will work and be responsive in the meantime and when a response arrives it will know what to do.
Not only your request, but the other's response
Okay, now that we think asynchronously, we need to consider our options to handle when the other player decides to join your game:
Polling
You may issue periodic requests to the server via setTimeout and AJAX requests and once the response notifies you about the game being accepted, handle it accordingly. See: https://davidwalsh.name/javascript-polling
Push notifications
The server may send notifications to the users once an event occurs. See: https://onesignal.com/lp-web-push?utm_source=google&utm_medium=cpc&utm_campaign=general&gclid=CjwKCAjw4_H6BRALEiwAvgfzq9s03BR1OhlvxwN6SCn6Q_bIKODk3bQK05gwdaHTpwvzV2d7mXQU9hoCSl4QAvD_BwE
But you may want to use something that's compatible with what you are using at the server.
WebSockets
WebSockets are duplex channels, which are kept open. If the framework is implemented and supported, then client A and client B would both be connected, client A would send a command via WebSocket, the server would receive that and notify client B via WebSocket. When client B decides to accept the challenge, he would click on the button, which would issue a command of his own to the server via WebSocket and the server would notify client A via WebSocket. See: https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
Summary
It's better to view this as a series of events and event handlers, rather than waiting for a response.

SessionStorage destroy event

From my (poor) understanding of the Web Storage, the sessionStorage object is maintained per-tab, it survives page reloads and page navigation, and it gets destroyed on tab close or browser process termination.
Is there a way to listen to the sessionStorage destroy event?
I need to perform an HTTP call when the tab or window is being closed and it seems the sessionStorage is the single object which follow a similar lifecycle.
Is there a way to listen to the sessionStorage destroy event?
No, there is no "destroy" event for session storage.
I need to perform an HTTP call when the tab or window is being closed and it seems the sessionStorage is the single object which follow a similar lifecycle.
You can't differentiate between page reload and navigating away from the page.
The only thing I can think of to get close to what you want to do is to do this:
In beforeunload or unload, use sendBeacon to do your HTTP call (it has to be a POST). You can't just use standard ajax (XMLHttpRequest/fetch), browsers are actively disabling standard ajax in unload events. So use sendBeacon if it's there, falling back to a standard (and — ugh! — synchronous) ajax request if it isn't (as that suggests and older browser were it may still work).
On page load, check sessionStorage for a marker and:
If it's there, do an ajax call basically saying "never mind!" to say that if the server just received an "I'm leaving the page" ajax call, it should disregard it.
If it's not there, set the marker.
You'll need to be sure that the server handles the possibility that, because of the vagaries of network requests (particularly as beacons are always asynchronous), the two requests may be received by the server out of order. So include some serialization information in them (for instance, a value from performance.now(), falling back to Date.now() if necessary).
Or, of course, use polling when the page is open and a timeout to indicate the user has left the page. The tradeoffs between the approaches will be fun to weigh. :-)
The user window.document (interesting username!) points out that you may be able to use web sockets for this. I don't have much experience using web sockets (must fix that!) but I think the general idea is that you'll see a socket disconnect when the user leaves the page or refreshes, but (like the above) if it's a refresh, you'll see a socket connection again very soon thereafter — which is like the "never mind!" call above.

Channel disconnect notification in channel api in google app engine

Im using my GAE application on my phone. I face a problem in getting the disconnect notification to /_ah/channel/disconnected in channels api even if i manually close the socket by socket.close() function. the post occurs after a delay of say one minute. Does anyone know the way to speed things up? In my case socket.close() doesnt produce the channel disconnect notification(only in phone though.. it works perfectly from a laptop)!
The amount of time it takes the Channel API front-end servers to "realize" that a channel is disconnected is contingent on browser implementation.
On well-behaved browsers, we catch the beforeunload event and post a message to our front-end that says, "this client is going away." On other browsers, we may not get the event (or we may not be able to listen to it for various implementation reasons, like the browser sends it too often (FFFUUUU IE)) or once we get the event the XHR we send may get swallowed. In those cases, the frontend server realizes the client is gone because it fails to receive a heartbeat -- this is what's happening on your phone. (out of curiousity, what phone?)
Your case is interesting because you're explicitly calling onclose. The only thing this does is dispose the iframe that has the Channel FE code -- in other words, onclose just behaves as if the whole browser window was closed; it doesn't take advantage of the fact that the browser is still in a good state and could wait to close until a message is sent.
So I recommend two things: add a custom handler to your code (that does the same thing as your /_ah/disconnect handler) so you can just make an XHR when you know you're manually closing the channel. This is kludgy but functional. The bummer about this is you'll need to explicitly know your client id in your javascript code.
Second, add an issue to our issue tracker (http://code.google.com/p/googleappengine/issues/list) to request better disconnect notification when onclose is called explicitly.
Hope that helps; sorry there's not an easy answer right now.

Can the unload Event be Used to Reliably fire ajax Request?

I need a method to monitor user edit sessions, and one of the solutions I'm reviewing will have me using an unload event to send an ajax request to inform the server of the end of the edit session. (See: Monitoring User Sessions to Prevent Editing Conflict)
My (rather limited) reading on the unload event indicates that the code attached to this handler has to run quickly, and as such, is usually used for clearing objects to prevent memory leaks.
My question is, can this work reliably enough for this purpose?
PS. I know about the async: false option.
This method is fairly reliable, if your server is fast enough to respond. Something to really watch out for though. If you close the browser and send AJAX request on unload event, there's a very good chance that the response isn't going to come back from the server in time before the window object is destroyed. What happens in this case (at least with IE) is that it will orphan your connection object and not terminate it correctly until the connection timeout is hit. If your server doesn't have connection keep-alive turned on, after you close 2 windows (while still having another window open), you will run out of open connections to the server (for IE6-7, for IE8 - 6 windows) and you will not be able to open your website until your connection timeout is hit.
I ran into a situation like that before were I was opening a popup window that was sending an AJAX request on unload, it was very reliable, but it was plagued by the issued described above, and it took really long time for me to track it down and understand what's going on. After that, what I did, is I made sure that opening window would have the same code to call server, and on every unload checked for the opener and ran the code there if it was present.
It seems that if you close the very last browser window, IE will destroy connection properly, but if one other window is open, it will not.
P.S. And just to comment on the answer above, AJAX is not really async. At least JS implementation of it isn't. After you send a request, you JS code is still going to be waiting for response from the server. It's not going to block your code execution, but since the server might take a while to response (or long enough for Windows to terminate IE window object) you might and probably will run into the problem described above.
Have you tried to use
var i = new Image(1,1);
i.src='http://...'
And just returning some empty image from server. I think it should be reliable, script will block. BTW: nice to add timestamp to prevent caching.
We have a case where we needed that. It's a report page that needs serious memory on the server so we wanted to free it immediately as soon as they left the page. We created a frameset and added the unload handler there. The most reliable way was to set the src of an image to the freeing script. We actually used both the unload and onbeforeunload for cross browser compatibility. It didn't work in web kit nightlies but management was OK with that.
However, that was not my proposed solution. I would use a heartbeat approach which involves more work but is much more robust.
Your page should send out periodical heartbeat requests. Each request sets the last heartbeat from a page. You then need a thread that runs on the server and clears memory if the last heartbeat was too long ago.
This doesn't solve the problem of leaving the page up for a long time. For that you need some monitoring for user activity and leave that page after a period of inactivity (make sure you confirm with the user)
You'll have to do your own testing about whether or not your particular scenario works with the time you have in unload, but making the AJAX request is pretty fast, since AJAX is asynchronous. You just send the request and then you're done! (Maybe you'll have to clear the request object you just created, though.)
If you wanted to verify that the AJAX request made it, then you'd have to worry more/use the async:false option (like this discussion indicates). But, just sending is a quick boom-and-you're-done operation.
I had a case in which I only needed to notify server side about the unload and didn't care about the response.
If thats your case you can ignore_user_abort and then you know it'll happen "reliably"

can client side Javascript detect when server has closed http connection while client is working?

In my application, the client is a Javascript set of functions in the browser, and it does some work - for example, playing a clip.
It uses XmlHttpRequest to talk to the server.
However, the server is allowed to abruptly close the connection since there is no other way it seems, to interrupt the client.
Can the client detect, while it is playing the clip, that the connection was closed, and so print a message and erase the page?
Any help appreciated.
thanks,
Anil
If the clip is streamed to the client, you could just stop serving it.
However, it seems like the clip is being downloaded and then played through the browser. In this instance it's probably best to use a watchdog approach as described by CookieOfFortune: Poll the server regularly (once a second or so) and get it to respond with tiny message of confirmation. When the connection is closed, get the server to respond with a negative messgage.
Unfortunately, without using a comet-like system, it's very hard to get the server to 'send' a message indicating session closure.
Bear in mind though, that as soon as the client has downloaded a clip they will be able to play it in full if they want to. Unfortunately there's no way to stop this besides switching to a streaming approach. If securing your content is a priority, I'd suggest making this change.
You can probably poll the XmlHttpRequest object, so just try to send a heartbeat every once in a while to see if the connection is closed. Otherwise, the server would have to send some signal to tell the client it is going to close the connection.
It does seem that the server cannot notify the client that the connection is closed; however the polling method suggested is not as efficient as a notification would have been.
I solved it by specifying that at the NEXT Get request, the client would be told that its session is invalid.
This was implemented by URL rewriting - appending "jsessionid=[id]" on each request sent by the Javascript functions. the servlet stores the current session id.

Categories