Understanding Closures: Constructing A Meta-function That Queues Functions Together
Solution 1:
The problem is how you were setting the value of cur_cont
for every new function you made, and calling cur_cont
in the onload
callback. When you make a closure like tmp_f
, any free variables like cur_cont
are not 'frozen' to their current values. If cur_cont
is changed at all, any reference to it from within tmp_f
will refer to the new, updated value. As you are constantly changing cur_cont
to be the new tmp_f
function you have just made, the reference to the other functions are lost. Then, when cur_cont
is executed and finishes, cur_cont
is called again. This is exactly the same function that had just finished executing - hence the infinite loop!
In this sort of situation, where you need to keep the value of a free variable inside a closure, the easiest thing to do is to make a new function and call that with the value you want to keep. By calling this new function, a new variable is created just for that run, which will keep the value you need.
function js_load(resources, cb_done) { var cur_cont = cb_done; array_each_reverse(resources, function(r) { // the stack of callbacks must be assembled in reverse order // Make a new function, and pass the current value of the `cur_cont` // variable to it, so we have the correct value in later executions. // Within this function, use `done` instead of `cur_cont`; cur_cont = (function(done) { // Make a new function that calls `done` when it is finished, and return it. // This function will become the new `cur_cont`. return function() { var x = document.body.appendChild(document.createElement('script')); x.src = r; console.log("loading "+r); x.onload = function() { console.log("js_load: loaded "+r); done(); }; }; })(cur_cont); }); // Start executing the function chain cur_cont(); }
EDIT: Actually, this can be made even simpler by using the Array.reduce
function. Conceptually, you are taking an array and producing a single function from that array, and each successive function generated should be dependant upon the last function generated. This is the problem that reduce was designed to help solve:
functionjs_load(resources, done) {
var queue = resources.reduceRight(function(done, r) {
returnfunction() {
var x = document.body.appendChild(document.createElement('script'));
x.src = r;
console.log("loading "+r);
x.onload = function() {
console.log("js_load: loaded "+r);
done();
};
};
}, done);
queue();
};
Note that reduce
and reduceRight
are not available for older browsers (<= IE8). A JavaScript implementation can be found on the MDN page.
Post a Comment for "Understanding Closures: Constructing A Meta-function That Queues Functions Together"