Preventing a browser from getting stuck on an AJAX request - javascript

I am currently trying to send a request when an user closes the page. I am using the onbeforeunload event.
The event triggers when the tab is closed or the page is refreshed. My event looks as follows:
window.onbeforeunload = function () {
$.ajax({ //jQuery
type: "POST",
url: "offline.php",
data: {
logout: 'false'
}
});
};
offline.php (this is not the complete script):
...
unset($_SESSION["onpage"];
if ($_POST['logout'] == "false") {
sleep(3);
if (isset($_SESSION["onpage"]) || !empty($_SESSION["onpage"])) die();
}
...
When a user closes the page, script unsets a session that is set on the page of the chat. After three seconds, the script should check if the user has returned but checking the onpage session. However, the problem comes in when I hit the refresh button. On refresh, the page does not load because the three seconds have completed. This is causing my whole system to be ruined.
I have tried adding ignore_user_abort(true); but it did not solve my issue. Is there any other way of getting this to work?
Side Note: This is for a chat. When a user closes the page, it should notify the other users on the chat with a "The user has left" message. This should not be displayed on refresh. When a user comes back to the page, it should notify the other users that the user has returned with a "The user has entered" message.

The Problem
I'm afraid what you're attempting to do isn't really possible, as there are many times in which onbeforeunload won't get called, due to browser implementation, user preference, your pet zebra knocking your computer off the table, etc.
From Mozilla's beforeunload documentation:
Note also that various mobile browsers ignore the result of the event (that is, they do not ask the user for confirmation). Firefox has a hidden preference in about:config to do the same. In essence this means the user always confirms that the document may be unloaded.
https://developer.mozilla.org/en-US/docs/Web/Events/beforeunload
The Solution
That doesn't mean handling users going offline is impossible, however.
Most chat web applications instead employ a heartbeat (a regular ping-like request), and use the distance between last ping to determine user disconnects. As an additional note, I would recommend allowing a wider window than three seconds to determine user disconnects, because there are many reasons a ping may not make it within a three second timeframe.
Implementation Strategy
You have a few options to implement a ping. Most commonly, people will use a window.setTimeout to invoke the ping, which will restart the window.setTimeout upon completion or failure, usually doubling the delay on successive failures so you aren't barraging a potentially-overloaded service.
setTimeout to Ping:
var i = 1000;
(function ping() {
$.ajax({
type: "POST",
url: "ping.php"
}).done(function() {
i = 1000;
window.setTimeout(ping, i);
}).fail(function() {
i = i * 2;
if (i > 60000) {
// We don't wait to wait longer than a minute
i = 60000;
}
window.setTimeout(ping, i);
});
}());
What about window.setInterval instead? Won't my code be shorter?
Please don't do that. My above note about "barraging an overloaded service"? It'll be plenty worse if you do that.

You really shouldn't be counting on onbeforeunload or beforeunload since a browser shouldn't require itself to do something on your behalf right before a user closes your webpage. If it did, it would open up a whole avenue of attack for malicious code where you could never close a page (think going to a torrent website and having 2 pages pop up every time you click on any DOM element, only now every time a user tries to close the tab, a recursive loop starts and prevents them from ever leaving without killing the browser through task manager).
Heartbeats
Most chat clients use a heartbeat system where the client automatically pings the server every x seconds. This method works - but it's costly and inefficient. You're forced to open and close new connections on a constant basis just to tell the server that you are still engaged.
Web Sockets
The contemporary way of building something like a chat system is to use web sockets. These are persistent connections established by the server between your web browser and the server. On a traditional web page, the server always reacts to the what the client does. The client makes a request, the server responds; this process repeats itself over and over again. The server never tells the client what to do and then wait for the client response. With web sockets, instead of having this one way communication channel, we have a pipeline that allows for a continuously open connection with bidirectional communication.
Creating Web Sockets
This isn't a trivial task. There's a lot of boilerplate code out of the gate you would have to write to get some basic functionalities working. But the good news is that you don't have to do this. There are several 3rd party JavaScript SDKs / back-end services that encapsulate all of the ground level browser implementation logic for you and make available to you a simple, clear interface. Think of their relationship to web sockets as what jQuery was to plain JavaScript. They standardize everything for you so you don't have to worry about writing low level web socket implementation and syncing up cross browser compatibility.
One of my favorite web socket services is Firebase. Coincidentally, the demo project they showcase on their website is a real-time chat application built using the web socket support their service provides. Firebase can be set up to be an indepedent database source if you want it to be that. Or it can simply be used as a medium of communications between your traditional SQL database (which communicates with it through a RESTful API) and client devices (browsers, apps, etc...).

I would like to point out that, as others have said, doing an AJAX request on the page unload event is highly unreliable.
However, you may be interested in Navigator.sendBeacon()
Relevant excerpt:
This method addresses the needs of analytics and diagnostics code that typically attempt to send data to a web server prior to the unloading of the document.
https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon
It is experimental, but once fully supported, should do what you want.

AJAX can get cut off as the page leaves.
You need to use navigator.sendBeacon() instead.
https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon
window.addEventListener('unload', function () {
navigator.sendBeacon("offline.php", {
logout: 'false'
});
}, false);
This is simple, reliable, and needs no server smarts like juggling heartbeats entails.
Of course, like anything good in webdev, IE compat is lacking...

Related

Updating a single page application built with AngularJS

I am creating a complex social networking website that is all one single page that never refreshes unless a user presses the refresh button on the browser.
The issue here is that when I edit files and upload them to the server they don't take effect unless the user refreshes the browser.
How would I go about and fix this problem? Should I do a time interval of browser refreshes? Or should I poll the server every 10 minutes to check if the browser should do a refresh?
Any suggestions?
Server
I would communicate the version number through whatever means you're already using for data transfer. Presumably that's some kind of API, but it may be sockets or whatever else.
Whatever the case, I would recommend that with each response - a tidy way is in the header, as suggested in comments by Kevin B - you transmit the current application version.
Client
It is then up to the client to handle changes to the version number supplied. It will know from initial load and more recent requests what the version number has been up until this point. You might want to consider different behaviour depending on what the change in version is.
For example, if it is a patch number change, you might want to present to the user the option of reloading, like Outlook.com does. A feature change might do the same with a different message advertising the fact that new functionality is available, and a major version change may just disable the site and tell the user to reload to regain access.
You'll notice that I've skated around automatic reloading. This is definitely not a technical issue so much as a UX one. Having a SPA reload with no warning (which may well result in data loss) is not the best and I'd advise against it, especially for patch version changes.
Edit
Of course, if you're not using any kind of API or other means of dynamically communicating data with the server, you will have to resort to polling an endpoint that will give you a version and then handle it on the client in the same way. Polling isn't super tidy, but it's certainly better - in my strong opinion - than reloading on a timer on the offchance that the application has updated in the interim.
Are you talking about changing the client side code of the app or the content? You can have the client call the server for updated content using AJAX requests, one possibility would be whenever the user changes states in the app or opens a page that loads a particular controller. If you are talking about changing the html or javascript, I believe the user would need to reload to get those updates.

Unsubscribe to a PubNub channel in response to (before)unload event

I am building a multi-players game in angular using the PubNub service, including the presence add-on.
Since I need to detect if someone left the game unexpectedly - in order to send a message to the other players and end the game - I am trying to unsubscribe a user when he refreshes the page or goes to some other url. However, in Chrome - as opposed to FireFox - no presence event is being triggered, which probably means that the user wasn't unsubscribed prior to his leaving of the page.
CODE:
$(window).bind("unload",function(e) {
PubNub.ngUnsubscribe({channel:$scope.game.channel});
e.preventDefault();
});
I am aware that these events (beforeunload and unload) are problematic and have poor browser support, which is probably the reason for the failure. If this is the case, is there any other cross-browsers detection method I can use?
There is no reliable way to catch the browser closing. The "beforeUnload" event is your best shot, but most mobile browsers don't trigger it. The best way to handle a user closing the browser in PubNub is to specify a heartbeat when subscribing (http://www.pubnub.com/docs/javascript/api/reference.html#subscribe). The heartbeat tells how many seconds PubNub should wait after an ungraceful disconnect (such as closing the browser), before considering a user as timed out. This is defaulted to 320 and can be set to as low as 6 seconds (> 5). It still won't be immediate, but you will receive a presence "timeout" action 6 seconds after the browser is closed. Having a low heartbeat could impact your battery life so be wary of that.
Also, I know I linked the doc to the JS API, but the angular ngSubscribe allows most of the same arguments.
Hope that helps.

On site notification system

I was tasked to build a calendar and agenda library (I'm working on the CodeIgniter framework), that shows a calendar and the user has the possibility to set events on that calendar.
These events will have a notification system both email, and when the user is browsing the site, a popup.
My issue is how to approach the notification part when the user is on the site. The email is something that I already decided would be done trough a cronjob that will run every x minutes and check if there is any need to send a notification email.
The on site notification is something else.
How would I approach this? I just can't make a ajax request to the server every x seconds, since that would put an unnaceptable load on the system. (Of course when the user is eventually notified, a request must be made, to set the user as "remined" on the database).
I can't just depend on the user's date time, since he could be anywhere in the world and the time would be different.
How can I check that the user must be notified of a event, avoiding making repeated requests to the server? Would appreciate any input.
I could see using setTimeout to do this. Say a user visits your page $minutesTilDue minutes prior the reminder being due. Assuming jQuery/PHP:
$(function(){
setTimeout(function(){
showEventReminder(<?php json_encode($event) ?>);
}, <?php echo $minutesTilDue ?> * 60 * 1000);
});
Nothing too fancy, but depending on your requirements...
Cheers
Easily scalable notification systems use websockets, which today reach the majority of the users, even on mobile devices. Unfortunately, you'll need a websocket-enabled server - node, glassfish, whatever - this can't be done with standard PHP deployments (mod_php or fcgi). Server events (so called server push) are sent when they are generated, so once you have your websocket client-server pair, sending a reminder is just like sending an email.
Actually things are more complicated because most likely users won't be online at the exact time the reminder should pop up. I suggest a notification icon which is refreshed each time the user hits a page. This way your calendar system (suppose a cronjob) will simply update a flag for the user row in the DB, and when you build the page, you already know if there reminders (let's say, in the next 60 minutes) or not, and choose the icon accordingly. At this point, you have two choices:
sending the reminders to the client along with each and every request (it could be a waste of bandwidth, but I don't thing a JSON-encoded list of events is so heavyweight)
Download the reminders asynchronously on demand, ie only when the user hits the notification icon
This scenario lets you reuse the PHP environment and code, and doesn't require another host for the websocket server. I think this is the best solution, even if this doesn't fulfill your requirement of a truly popup reminder triggered by the server at the right time. BTW, if you send events with every request, your javascript can pop up when needed - you can use setTimeout() for this.

Javascript Best Practise: Syncing Browser Windows

I have an html5/javascript application in which multiple users can be viewing the same set of data of any given time. For the sake of a real world example, lets say its a calendar type page.
So user1 is looking has the browser open and looking at the calendar page and user2 is also on the calendar page. User2 makes a change to the calendar and i'd like (as quickly as possible) for those changes the be recognized and refreshed on user1's screen. What is the best way to do this?
I'm thinking about have a mysql table for active users that stores the page they are currently on and a timestamp for its last update, then use ajax calls to ping the server every few seconds and check for an updated timestamp, if its newer than what they have client side, the new data gets sent and the page "reloaded." I am putting reloaded in quotes because the actual browser window will not be refreshed, but a function will be called via javascript that will reload the page. Sort of the way stack overflow performs its update checks, but instead of telling the user the page has changed and providing a button for reload, it should happen automatically. If user1 is working away on the calendar, it seems it might be quite annoying for user2's screen to constantly be refreshing...
Is this a horrible idea? Is pinging the server with an ajax request every few seconds going to cause major slow downs? Is there a better way to do this? I would like the views on either users side to be real time because its important that user1 not be able to update an element on the calendar page that user2 has already changed.
Update: based on some web sockets research it doesnt seem like a proper solution. First its not compatible with older browsers and i support ie8+ and second i dont need real time updstes for all users on the site. The site is an account based applicatiin and an account can have multiple users. The data needs to sync between those users only. Any other recommendations would be great.
You need realtime app for this. You should have a look at socketio. Everytime a user log in, you make him listen for changes on the server. Then when something changed on the server, every users listening are notified.
you can find examples on the official website : http://socket.io/

Server polling intervals for a javascript chat client

I'm building a basic little AJAX shoutbox/chat for my website, but I'm not sure exactly how to implement the server polling.
Here's the basic program flow I'm thinking of:
User comes to page and is shown the last 10 messages
To get messages sent by others, the client javascript would request a URL with a timestamp parameter (set to the value of the last message the client received)
The server returns all messages (up to a max of 10) since that timestamp.
The only issue is how often to poll the server. Obviously it should poll each time a new message is added, but when you're just reading others' messages it needs to automatically update.
Should it be a set time limit? eg: every 10 seconds. Or, should it vary depending on usage? eg: Check after 5 seconds. If there's no messages, don't check for another 10 seconds. If there's still no new messages, check in 15 seconds, then 20, up to maybe once every 30 seconds max. Each time there's a new message detected reset your timer back down to 5 seconds and start again.
I'm just concerned about putting unnecessary stress on the server, considering that we could have hundreds of users concurrently online.
...or have I got the whole thing wrong? Is there a better way to implement a basic javascript chat?
You might want to look into what are known as Comet programming techniques to stream information down to your users, rather than having the client poll the server. This is actually a family of techniques, some of which may work better than others depending on the circumstances, such as what kind of server you're using and what kind of client compatibility you need.
If your server can handle a large number of open connections at a time (as in, it does not use an entire thread or process per connection, such as nginx or an erlang based server), you may wish to use a long polling technique, where as soon one message is received, the client immediately requests another message. If there are no messages available, the server simply keeps the connection open, possibly sending occasionally dummy data as a keepalive, until a message becomes available.
Comet, described by Brian is a nice technique, but requires session support on the server, which is probably more advanced than you care to implement for a simple chat box.
The best way to implement polling intervals is to imagine you having a chat window which you can minimize to do other stuff, or open to see if you have new messages. When you are in the middle of a conversation, you'll switch to it (poll) frequently. If you don't get any messages for a while, you will start looking rarer and rarer until you only check it occasionally.
Assuming you don't need to do real-time typing, you can probably poll every 3 seconds or so when at peak activity, and if nothing shows up for 5-10 polls, start to crank the interval up (perhaps doubling it every time) until it hits 30-60 seconds. Getting a message back should reset the poll interval back to a few seconds, while sending a message should poll instantly, but probably doesn't need to effect the frequency of polling otherwise.
Honestly, if you are implementing a “basic little AJAX shoutbox/chat”, things like Jabber, Comet etc are overkill for you. These things will require you to run additional
servers/proxies to take the load of the app server and db.
When you think about stuff like presence management (“Joe is typing...”), then things get overly complex for your app (considering “chat” is not your prime focus).
Think about adding widgets from providers like Meebo and Userplane. Once you scale think about the Jabber and the like…
You should check to see if the other user is typing every 5 seconds or so, if the other user is typing, then you can check every 1 second to see if the user has sent a new message. Really though, you should be able to check every 1 second to see if other user is typing and if they are then every .25-.5 second check to see if new message has been sent. With broadband being so generally accepted on the inet, shouldn't be a problem. Go with the longer poll timeout for a dial-up access.
This is a very hard question, keep abuse in mind. Malicious users will hit you as often as possible, with the earliest timestamp faked so as to cause stress on your DB server. Be sure to validate that timestamp, or ignore it, because shouldnt everyone be in the same time anyway?
You can send the polling interval to the user as a function of the other user's response time. That's the best kind of dynamic I think.
http://jabbify.com/home/comet_service
This is a free comet based chat service by the guys who did the jmvc framework. Haven't tried it yet, but looks promising.
The professional way of doing this is with a WebSocket javascript connection. You can use a free service like https://socketsbay.com/ for example, and connect using
// Create WebSocket connection.
const socket = new WebSocket('wss://socketsbay.com/wss/v2/[ChannelId]/[ApiKey]/');
// Connection opened
socket.addEventListener('open', function (event) {
socket.send('Hello Server!');
});
// Listen for messages
socket.addEventListener('message', function (event) {
console.log('Message from server ', event.data);
});
You can forget about server pooling time because it will be realtime.

Categories

Resources