Wilsonhut

Deal with it or don't

Monthly Archives: June 2013

$.gasp is published!

jQuery Gasp is published. It’s almost as if they let just anyone on the internet. Am I right?

Advertisements

$.defer renamed to $.whereas, and published

Only because the name $.defer was already taken.

jQuery Whereas

A promisified, progress revealing, cancellable setTimeout

$.defer for advanced promise users – progress, only when you need it!

EDIT: $.defer was renamed to $.whereas

[If you’re not familiar with $.defer, you can go read about it, or just go look at the code.]

Let’s say you have an long-running script inside a function, and you only want to do that work once, even though the function might get called more than once. That function might look like this:

function initializeTheDifficultStuff(){
 if ($(".importantStuff").data("isInitialized")){
   return;
 }
 // Do the difficult stuff

  $(".importantStuff").data("isInitialized", true);
}

The difficult stuff might be some ajax or some other long-running, dom-manipulating javascript.

Now, lets say you decide to make that use the $.Deferred() / promise jQuery feature. Modifying the code above, you could do something like this:

function initializeTheDifficultStuff(){
  if ($(".importantStuff").data("isInitialized")){
    return $.when(); // $.when() returns a resolved promise.
  }
  var d = $.Deferred();
  // Do the difficult stuff
  $(".importantStuff").data("isInitialized", true);
  d.resolve();  
  return d.promise();
}

Now that doesn’t get you much, except the ability to use the .then/.done methods when you call initializeTheDifficultStuff(), since the ‘difficult stuff’ is not asyncronous. If the ‘difficult stuff’ was an ajax call, and you put the d.resolve() in its callback, then you’d have something.

I discussed all of this in a previous post, but now I want to take it a step further…

What if you want to use the progress callback to show a ‘please wait…’ message?

What if you want to use the above method like this? (Here, I’m using the $.blockUI plug-in)

initializeTheDifficultStuff()
  .progress(function(){
    $.blockUI();
  })
  .done(function(){
    //.. show something, do something else.
    $.unblockUI();
  });

The reason you might WANT to do that is so that you could keep the $.blockUI call from happening if the “isInitialized” is already set. That’s what you want, since it’s not going to have to do the hard work in that case, and the $.blockUI call starts a fade-in which would be unnecessary.

Now that gets more difficult with the above implementation of initializeTheDifficultStuff, because, unlike the done and then, events, the progress is never called on a pre-resolved promise. So what can you do? You can return the d.promise, like above, but just before that, put a call to d.notify and d.resolve in a setTimeout. That would start to look ugly real fast. I’m not even going to show that.

$.defer handles this all for you.

You can use the initializeTheDifficultStuff() with the progress and done events, and have clean looking code by using $.defer, like so:

function initializeTheDifficultStuff(){
  if ($(".importantStuff").data("isInitialized")){
    return $.when(); // $.when() returns a resolved promise.
  }

  $(".importantStuff").data("isInitialized", true);
  return $.defer()
       .then(function(){
         // Do the difficult stuff
       });
}

The $.when() returns a resolved promise, so your progress event handler doesn’t get called!
$.defer returns an un-resolved promise. And in this example, it would wait the minimum number of milliseconds, then do the magic. Here’s what it will do for you…
It will first cause your progress event handler to get called. Then it runs the ‘difficult stuff’ for you. Then it is resolved so that your done event handler gets called.

It’s all so pretty and neat, and you get the progress event only when you need it!

Go get the $.defer plug-in from github today!

Introducing… jQuery Gasp – Give a little breathing room to your browser-intensive jQuery

Have you ever done something like…

$("td").someBigNastyPlugin();

…and it was just too much processing for your browser? (I’m looking at you, IE)

It would be nice if your browser had a little bit of time to catch its breath while it’s trying to do all that processing.

jQuery.gasp to the rescue!

Include my gasp plug-in, and replace that code above with the following, and you’ll have a happy browser.

$("td").gasp(function(){
  $(this).someBigNastyPlugin();
});

Essentially, it’s like jquery’s .each function, but it puts a setTimeout around each one, and chains them together, one after the other. If you saw my defer plug-in, this will make more sense.

Now this is asyncronous, but it returns a promise, so you have to treat it accordingly:

$("td").gasp(function(){
  $(this).someBigNastyPlugin();
})
.done(function(){
  console.log("This will run when it's complete");
});
console.log("This will run before the gasping is finished");

The code for this plug-in is below, but the code below requires my jquery.defer plugin.

The jquery.gasp plug-in (on github) includes the jquery.defer code. Just seemed easier (for you) that way.

In later posts, I’ll show you some other cool things you can do with this other than give your browser a little relief. (Spoiler: Remember that $(…) can take things other than a selector string as an argument.)

;(function ($) {
    var defaults = {
		breathTime: 0,
		wait: 0
	};
	$.fn.gasp = function (func, options, promise) {
		options = $.extend({}, defaults, options);
		promise = promise || $.when();
		var isFirst = true;
		this.each(function () {
			var self = this;
			promise = promise.then(function () {
				var p = $.defer(function (el) {
					func.call(el);
				}, (isFirst? options.wait : options.breathTime), self);
				isFirst = false;
				return p;
			});
		});
		return promise;
	};
})(jQuery);

jquery-defer (a jQuery Deferred-ified/promisified setTimeout) is on github