//
// version 1
//
var requestAnimFram = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequsetAnimationFrame ||
function(callback){
window.setTimeout(callback, 1000 / 60);
}
})();
//version 1 usage
function main(){
//main loop
...
requestAnimFram(main);
}
main();
//
// version 2
//
var animFram = {
req: window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback){
window.setTimeout(callback, 1000 / 60);
},
ccl: window.cancelAnimationFrame ||
window.mozCancelAnimationFrame,
myReq: 0
};
//version 2 usage
function main(){
...
aniFram.myReq = aniFram.req(main);
}
main();
function stop(){
aniFram.ccl(myReq);
}
While I was exploring some example codes, I found requestAnimationFrame
. version 1 is carved from that and it works fine. After seaching for a while, I found cancelAnimationFrame
as well and wanted to use both of them. So I made a dummy page for test. The version 2 is carved from it.
The problem is that, it doesn't loop. So, I have two questions.
Is it impossible to use requestAnimationFrame
in this way? If so, why exactly so?
If it's possible-but I'm doing it in wrong way, how can I acheive this?
- Is it impossible to use requestAnimationFrame in this way? If so, why exactly so?
It is impossible.
- If it's possible-but I'm doing it in wrong way, how can I acheive this?
This problem, by itself, can be easily fixed by using call()
and bind()
and apply()
methods.
//Using call()
//Attach call method during invocation
aniFram.req.call(window, main);
//Using bind()
//Attach bind method during the object initialization
aniFram = {
req: requestAnimationFrame.bind(window)
...
}
aniFram.req(main);
//Using apply()
//Attach apply method during invocation
aniFram.req.apply(window, [main]);
Notice the similarity in here that all 3 methods somehow have an additional parameter 'window'. They all have a same reason for it: requestAnimationFrame
is a method of window
object that requires the context of window
.
aniFram
is an object. It has a method req
which references the window.requestAnimationFrame
. aniFram.req(main)
invokes the window.requestAnimationFrame
in the context of the aniFram
, not window
. That's why it doesn't work. Let's consider another example code:
var obj1 = {
target: 'Jake',
hitman: function(){
this.target = 'RIP';
}
};
var obj2 = {
//assigns obj1.hitman to obj2.hitman
hitman: obj1.hitman
};
obj2.hitman();
console.log(obj1.target); //outputs 'Jake'
/////////////////////////////////////////
//call() method
obj2.hitman.call(obj1);
console.log(obj1.target); //outputs 'RIP'
//apply() method
obj2.hitman.apply(obj1);
console.log(obj1.target); //outputs 'RIP'
//bind() method
var obj2 = {
hitman: obj1.hitman.bind(obj1)
};
obj2.hitman();
console.log(obj1.target); //outputs 'RIP'
This is exactly same situation as your code, version 2. You invoke obj2.hitman()
that references obj1.hitman
expecting to change the value of obj1.target
, but it does nothing. Because what obj1.hitman
does is executing a statement this.target = 'RIP'
. Since it is executed in the context of obj2
, this statement becomes obj2.target = 'RIP'
. There is no target
property in obj2.
That's where these methods kick in. Without them, Javascript Engine determines context automatically (current object. ie. aniFram, obj2). By attaching these methods to your code, now you can decide in which context it will be executed (ie. window, obj1).
This is also called as an Alias Function. (If Javascript has first-class functions, why doesn't this work?)