JQuery PeriodicalUpdater (AJAX long polling/server polling)

I’m working on an app that is using the JQuery JavaScript framework. Time came for a bit of AJAX long-polling (which I can no longer say without snickering thanks to WebDevGeekly), and so I went looking for a way to do that in jQuery: specifically, I wanted something like Prototype’s Ajax.PeriodicalUpdater, which has a nice decay to pull load off the server if not a lot is changing.

Unfortunately, such a beast doesn’t exist within the core JQuery code. I bitched about the lack of one on Twitter (cite), and ddelponte resisted routing me to http://letmegooglethatforyou.com/?q=jquery+periodicalupdater and instead pointed out the #1 hit on Google: 360innovate’s port.

That port didn’t do quite what I wanted, and I saw a few places to eke efficiencies out of the code, so I did. The new version of the code is hosted at http://github.com/RobertFischer/JQuery-PeriodicalUpdater/. Specific advantages over the 360innovate version are:

  • Any option in jQuery’s $.ajax can be used, including any callbacks. The only exception is the flag that treats modifications as errors. That’s always going to be true (see the next bullet).
  • 304 Not Modified pages are now treated like they weren’t modified (that is, timeout increases). Their treatment before was as errors, which caused the timeout to reset to the base value.
  • The settings passed into the function are now deep-copied, which means the setting object can be mangled after the call without hosing up the entire works.
  • As much work as possible is done up front, so the actual polling AJAX call is fairly fast and lightweight. This is important so that it doesn’t clog up the limited resource that is JavaScript user processing threads.
  • The first poll begins once the document has finished loading, which should speed initial page load and avoid issues caused by the AJAX response returning before the page is totally rendered.

The code for the PeriodicalUpdater is pretty cool. One stunt which people should definitely pay attention to is using executable code blocks for factoring out loop-invariant checks. In this case, it’s demonstrated in the logic to boost the decay:

        // Function to boost the timer (nop unless multiplier > 1)
        var boostPeriod = function() { return; };
        if(settings.multiplier > 1) {
          boostPeriod = function() {
            timerInterval = timerInterval * settings.multiplier;
 
            if(timerInterval > settings.maxTimeout)
            {
                timerInterval = settings.maxTimeout;
            }
          };
        }

In this case, this behavior is either a nop (for multipliers <= 1), or it's got some involved logic. The 360innovate version did the multiplier check each time the interval was going to be boosted, but that multiplier isn't going to change. Since the multiplier isn't going to change, the code can be factored out and the check can be saved.

The same functionality could be done by the function null unless there is logic attached, but then call points look like this:

if(boostPeriod) boostPeriod();

And I’ll take the overhead of a call to the nop method to get easier-on-the-eyes, more maintainable code.

This entry was posted in Classic, JavaScript, Open Source. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

84 Comments

  1. Posted June 25, 2009 at 10:20 AM | Permalink

    Hi Robert,

    (I’m the original plug in author :) )

    Nice work on refactoring the plugin. It was originally developed to fill a need for us, and there are definitely bits that could be re-thought.

    To be honest, this is probably something that should be added to the jQuery core, and I was surprised to learn that it wasn’t.

    Anyway, nice work, and I’m glad you were able to build on my original plugin.

  2. Posted June 25, 2009 at 10:39 AM | Permalink

    @John McCollum

    Despite my article in JSMag #1, my practical JavaScript Fu is pretty weak. Without the work you did, I couldn’t have done what I’ve done: I had no idea how to start writing such a beast, and your impl was nicely commented and very readable. So thanks for putting your stuff out there, and with such a great license!

  3. Posted June 26, 2009 at 12:21 AM | Permalink

    Just an FYI: a function call is pretty expensive in Javascript. Whether “expensive” is “more expensive than a conditional” is a different question though.

    • Posted June 26, 2009 at 7:28 AM | Permalink

      @Hsiu-Fan Wang

      I ignore any critique based on what is or is not “expensive” unless I see strong numbers. It’s nothing personal: it’s just that developers have bitched about everything being “expensive” at one point or another — all the way back to C. In fact, I imagine the first firmware developer was being told by their circuit-building coworkers that there was no way this “firmware” stuff could ever catch on, because it’s just too expensive to translate from electrical impulses to logic.

      The burden of proof required to get me to change it is this:
      1. Demonstrate it’s expensive enough that the user will actually notice.
      2. Demonstrate that the conditional is cheap enough that the user stops noticing.
      3. Demonstrate that the difference between the two is great enough that it is worth littering my code with repetitious logic structures and adding a potential maintenance trick.

  4. Posted June 26, 2009 at 7:47 AM | Permalink

    BTW, the PeriodicalUpdater is under active development in GitHub, so you probably want to track it there if you’re interested.

    http://github.com/RobertFischer/JQuery-PeriodicalUpdater/

  5. Posted June 26, 2009 at 9:02 AM | Permalink

    Oh, I see where there’s a bit of confusion.

    To clarify: the time interval logic was nontrivial and repeated, so it needed to be its own function in any case. Whereas the old implementation had that check inside (actually, two checks), the new implementation breaks out the two cases.

    I am *not* arguing that you’re better off creating functions and pre-calculating the implementation (basically hand window-optimizing). You might be, you might not be — don’t have numbers either way. But if you’ve got a function kicking around anyway, you might as well factor as much as possible out of the function, and since the function is just a variable, that variable can (and should) be redefined freely to provide the most specific implementation known.

    Note that the limitations to what can or can’t be known about the implementation are all mutable data questions. Clojure is increasingly convincing me that when it comes to sane, sturdy code, it’s not about static vs. dynamic typing stunts, it’s really about mutable vs. immutable data.

  6. Posted June 28, 2009 at 7:21 PM | Permalink

    Greetings Robert,

    A bit confused when I look at your example code in comparison to your README file. In the README file you describe the usage as “$.PeriodicalUpdater(‘/path/to/service’, {…”
    In the example you have “$.PeriodicalUpdater({url:”queryMe.html”},”.
    The first mangles any “sendData’ I include, and the second throws a fatal error. Trying to find out why that is, but have come to the decision that you’re in a much better position to discover it much more quickly than me. Appreciate your work, as well as John McCollumn’s!!

    Kenneth Stein

    • Posted June 29, 2009 at 7:50 AM | Permalink

      @Kenneth Stein

      The library API changed between this post and now. I got tired of having to use curly braces and the url key name, even if I didn’t have any other configuration options, so I pulled the URL out. This API will be consistent from now on.

      Not sure what you mean by “mangles any ‘sendData’ I include”. The PeriodicalUpdater wraps $.ajax directly, so you can use the configuration available to $.ajax. It doesn’t look like there is a sendData property: did you mean data?

  7. Posted June 29, 2009 at 11:17 AM | Permalink

    Thanks for your quick response Robert.

    SendData is one of the Settings for periodicalUpdater, namely an array of values to be passed – e.g. {name: “John”, greeting: “hello”}. SEE the README file.

    The example you provide at Github doesn’t use the sendData setting, and it doesn’t seem to be passing the information into the ajax call.

    John McCollum’s implementation passes the sendData setting infor without any problem. Something broke in the refactoring it seems.

    It’s awesome that you really got after this code and tightened it up. Just hoping that in doing so you haven’t uncovered something more problematic. Will be looking for your response.

  8. Posted June 29, 2009 at 11:25 AM | Permalink

    @Kenneth Stein

    I changed from using $.post/$.get to using $.ajax, apparently which changed the API due to inconsistencies on jQuery’s side1. Change “sendData” to “data” in your call and you’ll be fine. I’ve added a hack to route sendData into data in the GitHub version, too. But data should be preferred to sendData to retain consistency with $.ajax, which PeriodicalUpdater explicitly mimics.

    I’ve updated the README with the improved usage.

    1 Inconsistencies in jQuery’s API are its one deep flaw.

  9. Posted June 29, 2009 at 11:57 AM | Permalink

    Bingo! Thanks again Robert. Awesome!!

  10. Alex
    Posted July 2, 2009 at 5:39 PM | Permalink

    I don’t know if it should be like that, but i can’t use two updaters on one page.

    $.PeriodicalUpdater(‘/path/to/service’, {
    method: ‘get’,
    }, function(data) {
    // update div1
    });

    $.PeriodicalUpdater(‘/path/to/another/service’, {
    method: ‘get’,
    }, function(data) {
    // update div2
    });

    On this page only div1 will be updated with content from ‘/path/to/another/service’

    • Posted July 2, 2009 at 5:57 PM | Permalink

      I’m using it precisely that way on my client’s page: should work just fine. My guess is that you’re assigning and then re-assigning a variable, and the re-assigned version is getting used.

  11. Z
    Posted July 9, 2009 at 5:10 PM | Permalink

    is there an easy way to stop and start the service?

  12. Kris
    Posted July 24, 2009 at 4:37 AM | Permalink

    Hi
    I just tried example for the periodicUpdater but it didn’t load properly. Here are the details:

    Tested on IE 8.0.6001

    Webpage error details
    ——————————–
    User Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB6)
    Timestamp: Fri, 24 Jul 2009 09:28:44 UTC
    Message: Object doesn’t support this property or method
    Line: 3451
    Char: 4
    Code: 0
    URI: http://localhost/tmp/ajax/jquery/periodicUpdater/jquery-1.3.2.js

    I tried loading the jquery file from google and locally and got the same
    error both times.

     
    		<!-- script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"&gt;&lt;/script -->
     
    			$.PeriodicalUpdater({url:"queryMe.html"},
    				function(newData) {
    					$('body').append(newData);
    					$('body').append("");
    					$('body').append(new Date().toString());
    				}
    			);
  13. Posted July 24, 2009 at 4:39 AM | Permalink

    pls ignore the code at the end.. some of it got filtered by this noticeboad :)

  14. Posted July 24, 2009 at 10:06 AM | Permalink

    Are you using a version that’s got implicit variables in a for loop? IE8 balks on that sometimes.

  15. Posted July 25, 2009 at 3:50 AM | Permalink

    I guess you are not refering to a version of jquery since I got the same error loading the jquery from ajax.googleapis.com.

    It can’t be the brower since I tried it on Firefox 3.5.1 and chrome 2.0 but I just get blank pages there too. I am using your code from below

    http://github.com/RobertFischer/JQuery-PeriodicalUpdater/tree/master#

    I am using periodical updater out of the box too. Using firebug I get this message when i step through

    s.url.replace is not a function
    var ret = s.url.replace(/(\?|&)_=.*?(&|$)/, “$1_=” + ts + “$2″);\n

    This is the same line IE8 breaks on also. Others on this noticeboard don’t seem to have this problem report this so I am a little stumped.

    I hardcoded the url in periodicUpdater and I got another error regarding the console so I commented out the console logging and it goes into the update loop but the page is always blank. The url doesn’t seem to be picked up. It might just be my environment but I am really not sure what. I’ll try it elsewhere. Any ideas what it could be?

    Do you have a public test page with this code?

    As you might be able to tell I am new to jquery and haven’t touched js in years.

    Thanks in advance,
    Cheers
    Kris

  16. John Richards
    Posted October 1, 2009 at 6:51 PM | Permalink

    You might want to check out StreamHub Comet Server:

    http://www.stream-hub.com/

    It will do all the long-polling/server-push heavy-lifting for you.

    • Posted October 1, 2009 at 8:35 PM | Permalink

      @John Richards

      Yeah — unfortunately it’s non-costless version is hamstrung to be only useful for development. But if someone wants to spend some money on a solution, there you go.

  17. David
    Posted October 21, 2009 at 1:53 AM | Permalink

    Hi Robert,

    Trying your poller out to send post data to a php script which in turn returns a json encoded string.

    I keep getting 304 not modified all the time though, even at the first call. Tried settings headers on the php script (cache control, expires) to force updates to no avail.

    Any ideas?

  18. Posted October 21, 2009 at 8:26 PM | Permalink

    @David

    Can you put up a demo page showing the issue?

  19. David
    Posted October 22, 2009 at 4:46 AM | Permalink

    @Robert

    Let me get back to you as soon as I’ve got some more time. Went with setInterval for now.

  20. Posted October 26, 2009 at 11:38 AM | Permalink

    Hi Robert,

    Great contribution! It didn’t work out of the box for me though. I’ll put up a patch here:

    http://sunset.usc.edu/~mattmann/patches/jquery.periodicupdater.ajax.102609.patch.txt

    What it boiled down to is that my Web Service kept returning status == “notmodified” rather than status == “success”, and thus remoteData was never being set. From reading the jquery documentation, it seems that status == “notmodified” is a viable status return (when it’s a 302 or 3xx HTTP msg). So, my patch does an OR to check if status == “notmodified”, and it also checks ot make sure remoteData != null, and if it is, it uses the value of rawData as the current value (.success never gets called if status != “success”, so in that case, remoteData is never set).

    Hope this helps someone else like me!

    Cheers,
    Chris

  21. Posted October 26, 2009 at 12:30 PM | Permalink

    If the status isn’t modified, shouldn’t we take that to mean that it’s not modified and therefore the success route shouldn’t fire? Or are people having webservers returning 302 even when it’s new data?

    I’m applying the patch: we’ll see if that fixes the issues.

  22. Posted October 26, 2009 at 1:35 PM | Permalink

    Thanks Bob. I think normally the answer to taking 302 to mean “not modified” would be yes, but I’m seeing in Apache Tomcat 6.0.16 a return status of 302 from a web service even when new content is being generated. Might be a web server issue, but still if we catch this here, it makes the code more robust.

    Thanks a lot for applying the patch!

    Cheers,
    Chris

  23. Andrew
    Posted November 4, 2009 at 1:02 PM | Permalink

    This is excellent! Just what I’ve been looking for. It worked pretty much perfectly out of the box. The one question/problem I’m having is that I want to use a variable in the data that is updated every time the updater runs. Unfortunately, it keeps sending the original value as the data. The function and every other element on the page recognizes the updated data, but updater doesn’t use it.

    Am I out of luck? Any thoughts or suggestions?

    Thanks,
    Andrew

  24. Andrew
    Posted November 4, 2009 at 1:14 PM | Permalink
    $.PeriodicalUpdater('/build/'+la+','+lo, {
    	method: 'get',         
    	data: 'ltime='+varLtime,
    	minTimeout: 1000,
    	maxTimeout: 8000,
    	multiplier: 2,
    	type: 'html' 
    }, function(data) {
    		$('#loc+'-'+locid).html(data);
    		varLtime=$('#loc+'-'+locid+' .time:first').text();
    });

    So I want to pass varLtime in the data value. varLtime gets its value from an element on the page. I tried changing the varLtime variable in the data section to the actual jQuery selector. Then I also tried having the varLtime variable updated in the function after the data is retrieved. Either way, it doesn’t pass the data in.

    The locid is static, but the varLtime variable changes after each request.

    Thanks so much for your help! This is a great feature!

    Andrew

  25. Posted November 4, 2009 at 7:06 PM | Permalink

    @Andrew

    You’ve got an extra quote on the first line in your function (the syntax highlighting draws out the problem).

    The “data” value is evaluated only once, so of course you won’t see an updated value. There’s no functionality to dynamically calculate the data value, and that’s on jQuery: I don’t know a way to tell jQuery ot dynamically calculate the “data” value of the $.ajax call.

  26. Posted November 4, 2009 at 7:38 PM | Permalink

    @Andrew

    Actually, what to do just popped into my head. You should not be able to do this:

    $.PeriodicalUpdater('/build/'+la+','+lo, {
    	method: 'get',         
    	data: function() { return 'ltime='+varLtime; },
    	minTimeout: 1000,
    	maxTimeout: 8000,
    	multiplier: 2,
    	type: 'html' 
    }, function(data) {
    		$('#loc'+'-'+locid).html(data);
    		varLtime=$('#loc+'-'+locid+' .time:first').text();
    });

    Let me know if that works for you.

  27. Andrew
    Posted November 4, 2009 at 8:07 PM | Permalink

    Thanks so much for your help. Looks like adding a function for data does some pretty messed up things and breaks the script. (A whole host of errors and didn’t seem to return the data at all – even if it was just a text string.)

    I can get around some of this by changing the supporting services, but I was hoping to be able to do it in javascript.

    Thanks again for your help!

    Andrew

  28. Posted November 5, 2009 at 8:25 AM | Permalink

    @Andrew

    It works for me:
    http://demo.smokejumperit.com/demo.html

    Did you update the script to the newest version in GitHub?

  29. Andrew
    Posted November 5, 2009 at 9:05 AM | Permalink

    Just nearly amazing. Thanks!!

    Looks like it is working pretty well. The only problem is that everytime the updater runs it appends the data to the data. I’m doing this:

    data: function() { return ‘ltime=’+varLtime; },

    so, the request is:

    http://blahblah.com/blah.html?ltime=1234567

    then the next request is:

    http://blahblah.com/blah.html?ltime=1234567&ltime=1234569

    then the next request is:

    http://blahblah.com/blah.html?ltime=1234567&ltime=1234569&ltime=1234570

    and son on.

    Do you know of anyway to clear the data?

    Thanks again for all your assistance.

    Andrew

  30. Posted November 5, 2009 at 1:14 PM | Permalink

    I’m confused why that is true, and I’m not seeing that behavior on my example. Fire up a debugger (FireBug on FireFox is my favorite) and step through it. If the issue is in my code, let me know and I’ll fix it.

  31. Andrew
    Posted November 5, 2009 at 4:16 PM | Permalink

    Hi Robert,

    Thanks for your response. Yeah, it’s pretty strange. I use Firebug – which is how I saw the request going out with the appended and appended and appended data element.

    When I look at the demo I don’t see the data being included in the GET request while mine appends the data to the URL. When I set mine up like your demo (with the return ctr++) it also doesn’t include the data in the request and thus doesn’t append it to the URL. When I change it to return a string and the value then it gets appended. So, I think if the demo returned a string then it would append it over and over on the URL.

    Dose that make sense?

    Again, your help is much appreciated.

    Andrew

  32. Posted November 5, 2009 at 6:31 PM | Permalink

    @Andrew

    Oh, this is awesome.

    The problem is jQuery: it mangles the “url” parameter of the settings you pass in.

  33. Posted November 5, 2009 at 6:36 PM | Permalink

    @Andrew

    Issue is fixed in the code currently up on GitHub. Actually, a few issues are fixed. But it should be solid now. Check out the demo again: http://demo.smokejumperit.com/demo.html

  34. Andrew
    Posted November 5, 2009 at 11:37 PM | Permalink

    Oh excellent! Works like a charm! Brilliance! : )

    Thanks so much!

    Andrew

  35. Posted November 30, 2009 at 3:00 PM | Permalink

    Hey.
    I am having some issues with the json calls…

    When I use .ajax, or the 360innovate version data.length returns the number of objects, but when I use your code it returns the char count and treats it as a string…

    Any idea what is going wrong? I have been at this for hours!!!

    Many thanks :)

    • Posted November 30, 2009 at 8:00 PM | Permalink

      Use FireFox + FireBug and see what’s up with the return values. Is it what you expect? If not, what’s going on.

  36. Posted November 30, 2009 at 8:34 PM | Permalink

    the issue is that its returning as html content, and yes I did clear my cache and such.
    Also I simply replaced your file for the one from 360innovate, (only changing where I state the url) and it worked… but obviously yours is better so I would rather use that.

    *I also tried just using getjson() to test the data being returned by my php script and that worked without an issue…

  37. Posted November 30, 2009 at 8:42 PM | Permalink

    Are you specifying type:’json’?

  38. Posted November 30, 2009 at 8:43 PM | Permalink

    I sure am…

    • Posted November 30, 2009 at 8:47 PM | Permalink

      Hrm. Dunno. Don’t have time to debug this right now. Source is available (obviously)—let me know if you figure out what’s up.

  39. Posted December 1, 2009 at 1:58 PM | Permalink

    Ok so after a few hours, I cant figure out why the returned data is not being treated as json… so I created this (very hackish mod to the file)… it works, but thats about all I can say for it… I hope to go back and truly fix this soon…

    btw for the record, im using safari on mac.

    http://mattapperson.com/stuff/jquery.periodicalupdater.js

  40. J
    Posted December 12, 2009 at 6:05 PM | Permalink

    I use the following code. I wanted something that you could run without a lot of parameters, yet still retain the ability to override them when I need to. I too switched from Prototype to jQuery and needed to I also wanted a way to start and stop the timeout. This code has not been throughly in any sort of production environment.
    Hope this helps someone looking for a way to control the timeout. :)

    jQuery.fn.extend({
    	ajaxPeriodicUpdate: function(url, options, callback) {
    		var prevResp = null;
    		var events = {};
    		var defaults = {
    			url: url,
    			data: {},
    			type: 'post',
    			cache: false,
    			async: true,
    			dataType: 'html',
    			minFrequency: 2,
    			maxFrequency: 10,
    			multiplier: 2,
    			timerID: null
    		}
     
    		// Determine if options exist
    		if (options == null) {
    			options = {};
    		} else {
    			if (jQuery.isFunction(options)) {
    				// Assume that options is the callback
    				callback = options;
    				options = {};
    			}
    		}
     
    		var self = this;
    		var settings = jQuery.extend({}, defaults, options);  	
    		var frequency = settings.minFrequency;
    		var incrementFrequency = function() {return;};
    		if(settings.multiplier &gt; 1) {
    			incrementFrequency = function() { 
    				frequency *= settings.multiplier;
    				if(frequency &gt; settings.maxFrequency) {
    					frequency = settings.maxFrequency;
    				}
    			};
    		}
     
    		if (settings.complete) {
    			events.complete = settings.complete;
    		}
    		if (settings.error) {
    			events.error = settings.error;
    		}
     
    		settings.complete = function(xhr, status) {
    			if (status =='success' || status == 'notmodified') {
    				var respText = xhr.responseText;
    				if (respText == prevResp) {
    					incrementFrequency();
    				} else {
    					prevResp = respText;
    					frequency = settings.minFrequency;
    					self.html(respText);
    				}
    			}
    			if (events.complete) {
    				events.complete(xhr, status);
    			}
    			if (callback) {
    				self.each(callback, [jQuery.trim(xhr.responseText), status, xhr]);
    			}
    			settings.timerID = setTimeout(update, frequency * 1000);
      	};
     
    		settings.error = function(xhr, status) {
    			if(status == "notmodified") {
    				incrementFrequency();
    			} else {
    				prevResp = null;
    				frequency = settings.minFrequency;
    			}
    			if (options.error) {
    				options.error(xhr, statustatus);
    			}
    		};
     
    		function update() {
    			console.log('Updating at frequency of ' + frequency);
    			jQuery.ajax(settings);
    		}
     
    		jQuery.fn.ajaxPeriodicUpdate.stop = function() {
    			clearTimeout(settings.timerID);
    			settings.timerID = null;
    			prevResp = null;
    		};
     
    		jQuery.fn.ajaxPeriodicUpdate.start = function() {
    			if (settings.timerID == null) {
    				jQuery(function() {update();});
    			}
    		};
     
    		jQuery(function() {update();});
    		return this;
    	}
    });
  41. Posted January 11, 2010 at 9:28 AM | Permalink

    I’m going to take a look at implementing the functionality required by the “Can Has Biz?” system. I’ve left a comment over there asking why that functionality couldn’t be added to my version, but it’s still pending moderation. My guess is that someone was sucked in by the siren call of writing new code when extending old code works better.

  42. Posted January 14, 2010 at 4:24 PM | Permalink

    I got an error in your code, when using it for updating json-data. Error is only in IE (tested with v8). Firefox worked fine!

    Error (IE says syntax error) comes in line 125 of the code:
    if(ajaxSettings.dataType == ‘json’) remoteData = JSON.parse(remoteData);

    I think IE somehow automatically parses the json text to an object before the JSON.parse, so that remoteData is allready an array and can not be parsed as json-string!

    I ended up by changing this to
    if(ajaxSettings.dataType == ‘json’) {
    remoteData = JSON.parse(rawData);
    }

    This works fine for me in IE8 and Firefox.

    • Posted January 14, 2010 at 5:55 PM | Permalink

      @Jeff

      Sorry — I knew about that, but hadn’t pushed it to the repository.

  43. Posted January 15, 2010 at 2:41 PM | Permalink

    Very useful script – thank you! I had been hunting for a jQuery equivalent to Prototype’s periodical executor for a while. Finally found a solution rather than unresolved questions in forums. I may have a bash at creating a .stop() as that would be useful.

    • Posted January 15, 2010 at 3:19 PM | Permalink

      My recommendation for a .stop() would be to implement the ability to change the timeout (or other options) during runs, a la the “Can Has Biz?” solution.

      Once you’ve got that, .stop() consists of cranking up the time to wait to something ridiculously high or setting a “stop” flag.

  44. mike
    Posted January 20, 2010 at 3:40 PM | Permalink

    Hi Robert I have some feedback.

    I think this version of boostPeriod() is much clearer:

    var boostPeriod = function() {
    if (settings.multiplier > 1)
    timerInterval = Math.max(timerInterval * settings.multiplier, settings.maxTimeout);
    };

    Constructing an optimized version of a function can be a useful technique, but here saving a property lookup and comparison once every 1 to 8 seconds is way overkill.

    ===

    I’m curious, is it necessary to have success and error callbacks if you already have a complete callback registered? Complete should be called in either case, and is already checking the success status?

    ===

    trimming each xhr and checking for ‘STOP_AJAX_CALLS’ seems quite app specific, it should at the minimum be a setting thats turned off by default, and documented.

    Mike

    • Posted January 20, 2010 at 8:14 PM | Permalink

      Thanks for the feedback. I’m not working on the project right not, but if you fork, do the updates in GitHub, and send me a pull request, I’d be happy to pull in the new code.

      The trimming was required due to slop in the way xhr was implemented on some platform (trying to remember which). How trailing whitespace is dealt with is basically woefully inconsistent, so I trimmed for consistency.

  45. Posted January 27, 2010 at 9:46 AM | Permalink

    Another issue I ran into with:

    if(ajaxSettings.dataType == ‘json’) {
    remoteData = JSON.parse(remoteData);
    }

    is that it fails in Firefox <3.1 as it assumes native JSON. I looked at the way jQuery handle this in their own ajax function, and implemented it the same way (albeit with unsafe evaling of the JSON in the browser). The resulting modification is below:

    if(ajaxSettings.dataType == 'json') {
    remoteData = window.JSON && window.JSON.parse ?
    window.JSON.parse( remoteData ) : (new Function("return " + remoteData))();
    }

    • Posted April 1, 2010 at 3:28 PM | Permalink

      I’m really not a fan of the unsafe eval, and given Firefox is on the 3.6 series, I’m not sure I care to support Firefox < 3.1 with insecure code.

      If you’d like to work on your own version with that patch, feel free to fork the GitHub repo and share the forked repo’s URL here.

  46. Kurtis
    Posted March 31, 2010 at 3:00 PM | Permalink

    anyone has find a way to stop the script depending of the result from the server? like in the other version with : clearTimeout(PeriodicalTimer);

    • Posted March 31, 2010 at 3:44 PM | Permalink

      You can either call the .stop() method on the return value (see the README over on GitHub). There’s no way to do it from within a handler as of now, and I’m not entirely sure how I’d go about providing that functionality — maybe expose the handler to the callback functions?

    • Kurtis
      Posted April 1, 2010 at 11:54 AM | Permalink

      I don’t think I’m fallowing you correctly, because it seems that the polling continue, when I want it to stop.
      I used it like that
      $.PeriodicalUpdater(

      function(data) {
      if(data.fault != ”)
      data.stop();
      });

      • Posted April 1, 2010 at 3:23 PM | Permalink

        Calling data.stop() will prevent the next round of iteration. The timer itself isn’t exposed at this point, so you may get one more polling after the call to .stop, depending on when it is called. Although perhaps the handle’s .stop() method should also try to halt the timer…?

        • Kurtis
          Posted April 15, 2010 at 2:06 PM | Permalink

          so it’s normal if I get an error when I do that?
          data.stop is not a function in FF, or
          Uncaught TypeError: Object # has no method ‘stop’ in google chrome.

          • Posted April 15, 2010 at 5:33 PM | Permalink

            Oh, yeah. That’s because it’s not on data, but on the return value from the $.PeriodicalUpdater call—see the README.

            I’m not sure how to best expose that return value to the functions. Any tips appreciated.

  47. pat
    Posted April 14, 2010 at 9:30 AM | Permalink

    @commit 5d9c017 / comment 37053
    this breaks json parsing in IE 6

    I have to workaround that by setting type to text and doing JSON.parse in the callback. Looks like it is parsed twice, the json2.js I use throws an error in JSON.parse. Feel free to contact me for details.

    • Posted April 15, 2010 at 5:35 PM | Permalink

      So you’re using some external library to parse the JSON? Not terribly keen on that idea. I’m inclined to discontinue IE6 support (following Google’s lead)—or at least to say that IE6 with type=”JSON” doesn’t work b/c of limitations in IE6. But if there’s a clean workaround, I’m very much open to it.

      If you’d like to maintain an IE6-friendly fork, feel free and I’ll make a note about it in the README.

      • pat
        Posted April 16, 2010 at 7:20 AM | Permalink

        The external JSON lib is needed to work around the missing native JSON support in older browsers (IE < 8, Fx < 3.1/3.5)

        Those browsers just don't know what JSON.parse() should do so there's no way of using json there without one of the libs

        Anyway, the text type + parsing the json in the callback func works fine. If this is the only case where that part of the code fails it should be ok to mention that in some known-issues list and leave it as is.

        • Posted April 17, 2010 at 4:54 PM | Permalink

          It’s really less than IE 8? Boo. We probably should do something smart to support it, then…

          • Posted April 21, 2010 at 9:16 AM | Permalink

            Yes, it seems like it did appear in IE8:

            http://blogs.msdn.com/ie/archive/2008/09/10/native-json-in-ie8.aspx

            It is the same problem with early firefox that I mentioned above. I don’t like ‘insecure code’ either, however, as long as I have customers using IE<8 and firefox < 3.1 I have to make sure stuff works for them.

            My personal attitude is that doing things the same way jQuery does will introduce no *new* security flaws hence my fix used code copy and pasted from how they handle JSON objects. It's still not secure, but I feel that the solution used by jQuery is at least well understood and was probably the result of extensive debate and thought.

  48. Kenn Herman
    Posted April 23, 2010 at 6:05 PM | Permalink

    It would be nice to be able to silence pu_log with a debug : true || false.

  49. Lyon
    Posted April 26, 2010 at 12:47 PM | Permalink

    I’m trying to make PeriodicalUpdater stop once an error is received but nothing I try works.. Is there anything wrong with the way I’m doing this? Or does the stop() method not work with JSON data type?

    $.PeriodicalUpdater('file.php', {
    // options not included here, apart from the data type being JSON
    }, function(data) {
      if (data.error) { data.stop(); }
    }

    Thanks :)

    • Posted April 26, 2010 at 3:03 PM | Permalink

      .stop() hangs off the return from the $.PeriodicalUpdater call. I haven’t implemented an accessible stop() method from within the functions. Not entirely sure how to mangle them like that.

      • Lyon
        Posted April 27, 2010 at 12:02 AM | Permalink

        Thanks Robert. Looks like there’s no way to stop it for me then. Hmm… Do you know if PeriodicalUpdater works in IE? I can’t seem to get it to work in IE at all. Doesn’t update…

        Thanks for this nice plugin btw. :)

        • Posted April 27, 2010 at 7:32 AM | Permalink

          See the conversation above: built-in JSON apparently didn’t hit IE until IE 8, so JSON is only supported in IE 8 or above at this point. Still trying to figure out a good solution for that.

          If you’ve got a suggestion for how to expose a stop() method to the callbacks, I’d like to hear it. It’s a popular request.

  50. Posted May 5, 2010 at 12:12 PM | Permalink

    This is really useful — thanks for all your hard work.

    One problem I’ve noticed in Firefox is that memory starts to leak quite substantially with low minTimeout values (e.g. 500 — with maxTimeout: 5000).

    I’m using Firefox 3.6 on Windows XP SP3. Safari *seems* OK — Chrome likewise.

    • Posted May 24, 2010 at 2:34 PM | Permalink

      I think this was just fixed: someone implemented using reset_timer instead of set_timer all the time.

  51. Kenn Herman
    Posted May 24, 2010 at 12:57 PM | Permalink

    I hate to ask it again, but is there any chance that you might be taking off the console output:

    Error message: notmodified (In ‘error’)
    Status of call: notmodified (In ‘complete’)

    While debugging your own application, it sometimes adds unneeded noise. I guess I can do this myself, but just thought it should be an option in the codebase.

  52. Peter Campbell
    Posted June 11, 2010 at 5:31 AM | Permalink

    Great work! Do you know of any reason why using this with ASP.NET setup would cause 500 internal server errors to be sent back on each poll?

    Could it be because there is no contentType: “application/json; charset=utf-8″, part in the settings? ASP.NET web service calls from jQuery seem to need that.

  53. Ollie
    Posted July 17, 2010 at 6:14 PM | Permalink

    Is it possible to modify the updater while it’s running? Specifically, I’d like to change the url based on the data returned. Could you advise how to do that?

    Thanks for the great work – should be included in the jQuery core!

  54. Dave
    Posted August 2, 2010 at 12:30 PM | Permalink

    Hi Robert,

    This has been a life saver! We’re using this to update about 20 various items within a page, we have a loop that goes through and initiates the PeriodicalUpdater, however many times based on the loop.

    Is there a way to reset the updater? For example, if a user clicks on particular item, reset the updater?

    Thanks!

  55. Nick
    Posted August 23, 2010 at 8:31 AM | Permalink

    Hi,

    Have a problem with latest version and jquery 1.4.2 which i’ve just started using, the ‘data’ option isn’t being processed correctly, i’m calling it with a URL (in my case ‘/events/offset/’) with method GET and using a integer mvariable.toString() for the data option argument. Now according to http://api.jquery.com/jQuery.ajax/ the URL should be appended with the ‘data’ argument but it’s not happening for me – i’m just seeing /events/offset called again and again even though the myvariable is changing.

    I added console.log(ajaxSettings) on line 79 and can see that data has the correct value and appears to be a string but the ajax call is not modifying the url and appending this value… any clues, i’m new to both js and jquery so my knowledge of it’s datastructures and inheritance is a little poor :)

    Thanks
    Nick

  56. Nick
    Posted August 23, 2010 at 5:47 PM | Permalink

    If there is a proper solution i still would love to know, but for the time being i’ve added

    if(typeof(options.dynurl) == ‘function’) {
    toSend.url = options.dynurl();
    }

    into the getdata function and define an anon function on the options.dynurl to generate the correct url. couldn’t figure out the correct jquery way to do it, nothing worked, , jquery also assumes specific url schemes (using ? and & etc) which wont help even i could get it working.

    Maybe my usage or bug perhaps but a big one, surprised its not in their bug tracker…

7 Trackbacks

  1. By Cry for Help | Enfranchised Mind on August 13, 2009 at 1:21 PM

    [...] jQuery PeriodicalUpdater should be updated to use jQuery.ajax’s dataFilter to track if changes have occurred in the [...]

  2. [...] just released an update to GORM Labs and JQuery PeriodicalUpdater (which was introduced in this post). While the modifications to GORM Labs were improvements, the JQuery PeriodicalUpdater update ended [...]

  3. [...] jQuery PeriodicalUpdater, which has been getting lots of love because of feedback and support over here, has a new feature. The “data” configuration argument now will work properly with [...]

  4. By boncey.org - Machine tags on Flickr on November 28, 2009 at 10:01 AM

    [...] could use to show me the status of my re-tagging action (I had about 1700 photos to tag) and found JQuery PeriodicalUpdater so I wired that up to give me a countdown. The last thing to mention is the photodb:id machine tag [...]

  5. [...] couple updates to the jQuery PeriodicalUpdater (original post): the $400 update and a yet-more-succinct Updater API (not a huge fan of that name, but it’s [...]

  6. [...] server for another project we’re working on (to be announced soon). I started off using the PeriodicalUpdater from enfranchised mind, but I ran into some limitations that were problematic enough that I implemented a new version from [...]

  7. By jQuery Rolling and Polling | tips & tricks on August 17, 2010 at 2:20 PM

    [...] Fischer updated 360innovate’s plugin in JQuery-PeriodicalUpdater. The usage changes a little bit, and it plays better with jQuery’s [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">