This article focuses mainly on solving 3 problems:
- Apply long-polling technique using jquery ajax() function.
- Stop and restart long-polling when clicking on a UI element
- Prevent clicking too fast on the UI element
I am implementing an application with the requirement of being able to display a bunch of “real-time” data. Alright, real-time was exaggerated, I just need to update the display value every second. The long-polling technique (see also: push technology ) jumped to my mind at first. While a true push is not possible without the server side support, one can however emulate it using recursive ajax call with normal http request but with slower frequency.
(function longPolling(){ $.ajax({ url: "server", dataType: "json", data: { param1:"param1", name:"name" } success: function(data, statusText, jqXHR){ //processing data... }, }).done(function(data, statusText, jqXHR){ setTimeout(longPolling, 1000); }); })();
The code above will work. But the real requirement was that the old long-polling need to be stopped and start a new long polling immediately with new parameter when clicking on a new button or new folder or something. So I keep the parameter “name” which is in my case the clicked button/folder in the “lastClicked” variable and use it to control the long-polling:
var lastClicked, clicked; $("#tree").fancytree({ source: { cache: true, url: basePath + "type=devices", mimeType: "application/json; charset=utf-8" }, click: function(event, data){ clicked = data.node.title; if(lastClicked != clicked){ (function longPolling(){ if(!lastClicked || lastClicked===clicked){ $.ajax({ url: "server", dataType: "json", data: { param1:"param1", name:clicked } success: function(data, status, xhr){ //processing data... lastClicked = clicked; }, }).done(function(data, status, xhr){ setTimeout(longPolling, 1000); }); } })(); lastClicked = ""; } } });
I used the jquery plugin fancytree to build a tree structure, and when I click on the tree element, I will get the title of the element which is the parameter of the long-polling call. You will see that the lastClicked variable will never be cleared within the longPolling() function, unless another click event starts.
The logic is described as follows:
- the long-polling will start only when a tree element was not clicked last time
- the long-polling will repeat only when there is no click on the new tree element
To prevent clicking too fast on the tree element, meaning, too many ajax calls start at a very short time, you need to add extra mechanism with new global variable processing, the solution below looks over-design, but I believe it’s necessary, because if the timeout is very short like 1ms period, the “precessing” variable will be set very frequently to true/false, so we need to invalidate the too fast clicks with “return false” to prevent the not awaiting behaviours like program hang:
var lastClicked, clicked, processing = false; $("#tree").fancytree({ source: { cache: true, url: basePath + "type=devices", mimeType: "application/json; charset=utf-8" }, click: function(event, data){ if(processing==true){ // prevent clicking to fast return false; } clicked = data.node.title; if(!processing && lastClicked != clicked){ (function longPolling(){ processing = true; if(!lastClicked || lastClicked===clicked){ $.ajax({ url: "server", dataType: "json", data: { param1:"param1", name:clicked }, success: function(data, status, xhr){ // processing data... lastClicked = clicked; } }).done(function(data, status, xhr){ processing = false; setTimeout(longPolling, 1000); }); } })(); lastClicked = ""; } } });
In fact, I hate so many global variables. If you have better idea the fix this, please don’t hesitate to tell me, thanks in advance. 🙂