I need a simple engine that tells me when some animations (but could also be ajax call or anything that has some kind of “onComplete” function) finsh, when all of the registered animation has finished i mean.
I wrote a simple jsFiddle.
And I have some doubt:
-
Why I can’t writethanks to this answer i have resolved with “this duplication in self” (how can i call this method?)this.iorthis.finishbut I have to useEngine.iorEngine.finish? Is there a better way to write such a simple class? I have tried to document a bit here but it is still not clear. This inside Engine is a div because it is called inside a$("#somediv").bind('click', function() { })but I don’t know if the use of a static (??) variable on the object Engine is the right way to handle it. -
can jquery deferred object help me in this case? maybe there is a more simple and more effective way to write it with deferred object. I need something that i can invoke on anything (animation, on done on preloading, ajax)..
hope it is clear.. any advice or link to something that handle similar situations is appreciated!
last code
now the last code:
engine = new Engine();
$("#clickme").bind('click', function() {
$(".bar").each(function() {
engine.add()
$(this).animate({width:200}, getRandomInt(500, 3000),
engine.oncomplete);
});
});
// animation engine
function Engine() {
var self = this;
this.i = 0;
this.add = function() {
self.i++;
}
this.oncomplete = function() {
self.i--;
if(self.i<=0){
self.finish();
}
}
this.finish = function() {
alert("done!");
}
}
UPDATE:
I took a closer look at your fiddle. A couple of things needed fixing. You’re defining all methods inside the constructor. Just don’t do that: each and every time you create an instance, you’ll create the same functions over and over again. That’s just total overkill. Here’s a working fiddle, where all methods are prototype properties.
There was one line in particular that was causing some problems:
Here, you’re passing a reference to the
oncompletemethod as a callback, but the context in which the function object is invoked is determined ad-hoc, so this wasn’t referencing the instanceengineanymore, but that’s an easy fix: just use a wrapper function:An alternative approach would be: a closure (like you, perhaps unknowingly, created with
var self), that overrides the prototype method:Either way, that’s all it takes. Here’s some more info on the matter – I think.
There are still a few things that can be tweaked a little, but on the whole, I think you’re well on your way. Do remember: methods are best kept well clear of the constructor. if the second option is a bit vague (which it is, IMO).
I’ve promised myself that this will be the last link I’ll add to this answer: I’ve asked a question a while back on memory-leaks in JavaScript, it’s another one of my gargantuan posts, but just have a look at some of the code snippets: look at how the function
reusableCallbackis invoked, also take a look at the “answer” I posted to my own question, there’s an example of how nativeprototypescan be used. And if ever you’re bored, or if you’re interested: try reading the code and work out whatthiswill reference at any given time. If you can work that out, I think it fair to say that you know the basic principles by which JS determines the scope.You can’t write
this.finish, simply becausethisdoesn’t have a property calledfinish. Just change:to
Why? Simply because JS functions are first-class objects (they can be assigned to variables, well references to function objects anyways, they can be passed to functions as an argument, they can be the return value of a function, etc…)
Just try
console.log(Engine instanceof Object);, it’ll log true. So what you’re doing is this:But, when you create a new Engine object:
JS checks the prototype of whatever object
Engineis referencing, in this case: it references a function. The function is called using thenewkeyword, so JS will create an object. For this, it needs prototypes (and lots of them). The prototype of this particular function (constructor) hasn’t got any properties defined, so the JS looks for the next prototype in the chain, theObjectprototype. All methods and properties of that prototype are passed down to the new instance (trymyEngine.toString();andObject.prototype.toString === myEngine.toString, you’ll notice that they share the same method).Note that this is not entirely true/accurate, and isn’t even 10% of all the things that are going on when you’re creating a new object from a constructor, but it may help you understand a few of the things to come:
Suppose you want every new instance to have a
finishmethod, and -as you know- all new Engine instances inherit methods that are in theObject.prototype, you might thing of doing:It’ll work, sure enough, but so will this, then:
someArray.finish! Yes, arrays are objects, as are functions, references to DOM elements and what have you. So Don’t change the Object prototype!Instead JS allows you to define certain methods on a prototype level that is shared by all instances of that particular constructor:
This will create a basic prototype chain that looks like this:
So whenever a new instance is created, that new instance is assigned whatever properties are defined in the prototypes. As an upshot, a method can be created once (rather than inside a constructor, which creates a new function for every instance), and all instances will share that method. but refer to MDN for more details
Just this one thing: JS accesses an objects properties in the same way an object is created, except that the order is reversed:
When invoking
newEngine.finish, JS will first look to see if that instance has its ownfinishproperty, if not theEngineprototype will be examined, if that doesn’t have a finish method either, JS will carry on through the prototype chain until the desired property is either found (all the way up to theObject.prototype), or, if event the Object prototype doesn’t have the property, it’ll just returnundefined, which says it all, really: this property isundefined.As an upshot of this, you can mask prototype methods/properties as long as you need them to act differently than their default behaviour, and after that simply
deletethe modified method. Here’s a real-life example:JS does its usual routine: check instance for
toStringmethod, and finds it. The function is called, and a neat JSON string is sent. After that, thetoStringmethod is deleted.JS searches for that property, on the instance itself. The method is deleted, so the toString method of the prototype is no longer masked, the next time it’s called, JS will do the same trick, but instead of finding the method on
data, it’ll scan the prototype and normal service is resumed.I do hope this answer isn’t too chaotic, but I’m Very tired, so if it is: I’m sorry