Skip to content

Instantly share code, notes, and snippets.

@conradz
Created April 5, 2013 20:16
Show Gist options
  • Save conradz/5322280 to your computer and use it in GitHub Desktop.
Save conradz/5322280 to your computer and use it in GitHub Desktop.
Global Delay State

Since thinking more on the function/delay implementation, I've come to the conclusion that it basically is unusable in many cases when it caches functions globally.

Simple Example

function Item(el) {
  this.el = el;
}

Item.prototype.resize = function(width, height) {
  $(this.el).width(width).height(height);
}

function Application() {
  this.nav = new Item($(".nav"));
  this.body = new Item($(".body"));
}

Application.prototype.resize = function() {
  delay(this.nav.resize, 200, this.nav, 150, 500);
  delay(this.body.resize, 300, this.body, 500, 500);
}

var app = new Application();
app.resize();

Can you guess what the result is? The .nav element is unchanged, but the .body element is changed. This happens because this.nav.resize === this.body.resize, since it gets .resize from Item.prototype. The two delay calls needn't be together, they could be in entirely different parts of the app, on different objects, but as long it gets the same function from the prototype with 200ms it will not work. This IMO makes it way too easy to mess up with it. Functions should be designed to be easy to use, while making it harder to write obviously incorrect code.

Functional Example

The solution to the first example would be to cache the context property also, but this breaks down if not using an OO approach, as in the following:

function resize(el, width, height) {
  $(el).width(width).height(height);
}

function Application() {
  this.nav = $(".nav");
  this.body = $(".body");
}

Application.prototype.resize = function() {
  delay(resize, 200, null, this.nav, 150, 500);
  delay(resize, 300, null, this.body, 500, 500);
}

var app = new Application();
app.resize();

While this example is more obvious when considering overrides, it still is something that could happen, especially when using a function from another module (e.g. resize could be a complex function from a separate module). It is not that hard to imagine something that causes this, and the time to track down a bug like this can be extremely hard (timing bugs are some of the worst to track down). Imagine if you were doing an animation that called delay to wait for 10ms before moving it a little. If you had a condition like this the first animation could move at least one step, maybe more, but when the second animation started it could stop the first half-way through the animation. It would be extremely unlikely that you will immediately know that the cause of the animation getting stopped was because you were using delay to call a function on the prototype and that it was getting overriden.

Locally Cached Example:

IMO the cost of debugging and the ease of incorrect use outweighs the slightly more code of caching it locally:

function Item(el) {
  this.el = el;
}

Item.prototype.resize = function(width, height) {
  $(this.el).width(width).height(height);
}

function Application() {
  this.nav = new Item($(".nav"));
  this.body = new Item($(".body"));
  
  var resizeNav = delay(this.nav.resize, this.nav);
  var resizeBody = delay(this.body.resize, this.body);
  this.resize = function() {
    resizeNav(200, 150, 500);
    resizeBody(300, 500, 500);
  }
}

var app = new Application();
app.resize();
@conradz
Copy link
Author

conradz commented Apr 25, 2013

Just saw your comments, I don't get email notifications on the gist either :|

Yep, agree with getting timeout in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment