K
K
Kasheftin2011-03-23 17:11:13
JavaScript
Kasheftin, 2011-03-23 17:11:13

Problem with closures in javascript?

I write dynamic loading of javascripts. There is a list of filenames to be loaded and a list of callbacks to be executed after the download. Type:

onload_js = [];<br>
onload_js[onload_js.length] = {"src":"script1.js","callback":function() { callback1(); }};<br>
onload_js[onload_js.length] = {"src":["script2.js","script3.js"],"callback":function() { callback23(); }};<br>

This means that you need to load script1.js, then execute callback1, and you also need to load script2.js and script3.js, and when both are loaded, execute callback23.

I loop through all onload_js and load the scripts through the $.getScript jquery method. The problem is that I don't know how to correctly make a closure inside the callback of the $.getScript method.

Type:
for (var i in onload_js) {<br>
  for (var j in onload_js[i]["src"]) {<br>
    $.getScript(onload_js[i]["src"][j],function() {<br>
      if (//Здесь проверка что все остальные скрипты загружены тоже)<br>
        onload_js[i]["callback"]();<br>
    }<br>
  }<br>
}<br>


This is without a closure. And it is clear that the i parameter is not passed inside the nameless function. And everything does not work, because the callbacks are called in the order they want. But write
$.getCode(onload_js[i]["src"][j],function(i,j) {<br>

it is impossible, because then variables from the ajax-response getCode come to i, j (i.e. the status of the response and the content of the file). If we wrap the nameless function in parentheses and call call(i,j), then the i,j parameters are passed correctly, but the scripts themselves are not loaded (callback1 and callback23 are not defined).

What to do?

Answer the question

In order to leave comments, you need to log in

7 answer(s)
A
Anatoly, 2011-03-23
@taliban

var callback = function(x,y){
  return function(){
    // x = i
    // y = j
    if (//Здесь проверка что все остальные скрипты загружены тоже)
        onload_js[i]["callback"]();
  }
}
$.getScript(onload_js[i]["src"][j], callback(i,j) )

I write the code from memory, but I think you will understand the principle, at least you will know which callback was called

P
pxx, 2011-03-23
@pxx

The $.getScript doc says:

This is a shorthand Ajax function, which is equivalent to:
$.ajax({
url: url,
dataType: 'script',
success: success
});

And in turn, in the dock about $.ajax there is a context parameter:
This object will be made the context of all Ajax-related callbacks

Thus, you can try to do this: I wrote on my knee, because it will take a long time to recreate your example, but I hope it should take off.
for (var i in onload_js) {
for (var j in onload_js[i]["src"]) {
$.ajax(
url: onload_js[i]["src"][j],
dataType: 'script',
context: onload_js[i],
success: function() {
if (//Здесь проверка что все остальные скрипты загружены тоже)
this["callback"]();
}
);
}
}

A
Anton Korzunov, 2011-03-23
@kashey

function fireAllInRealOrder(){
for (var j in onload_js[i]["src"]) {
onload_js[i]["callback"]();
}
}
for (var i in onload_js) {
for (var j in onload_js[i]["src"]) {
$.getScript(onload_js[i]["src"][j],function() {
if (//Здесь проверка что все остальные скрипты загружены тоже)
fireAllInRealOrder();
}
}
}

what's stopping you from doing it differently?

D
Dmitry Dedukhin, 2011-03-23
@Demetros

If I understand correctly and you need to pass the current value of i, then

(function(i) {
  onload_js[i]["callback"]();
})(i);

D
Dmitry Dedukhin, 2011-03-23
@Demetros

more precisely

(function(i) {
    $.getScript(onload_js[i]["src"][j],function() {
      if (//Здесь проверка что все остальные скрипты загружены тоже)
        onload_js[i]["callback"]();
    }
})(i);

P
pxx, 2011-03-23
@pxx

By the way, the for (var i in onload_js) construct is dangerous: i, in addition to the values ​​[0, 1], will take parasitic names of methods and properties of the Array object: $family, each, clean, associate, link, contains, extend, getLast, getRandom , include, combine, erase, empty, flatten, hexToRgb, rgbToHex, toJSON.
To avoid this, an additional wrapper check is needed:
for (var i in onload_js) {
if (onload_js.hasOwnProperty(i)) { /* do something */}
}

M
mnasyrov, 2011-03-23
@mnasyrov

var onload_js = [];

onload_js.push({
  "src": ["script1.js"],
  "callback": function() { callback1(); }
});

onload_js.push({
  "src": ["script2.js", "script3.js"],
  "callback": function() { callback23(); }
});

function myCoolLoader() {
  for (var i = 0; i < onload_js.length; i++) {		
    var scripts = onload_js[i];		
  
    for (var j = 0; j < scripts.src.length; j++) {
      var url = scripts.src[j];
      
      $.getScript(url, function() {
        if (/*Здесь проверка что все остальные скрипты загружены тоже*/) {
          scripts.callback();
        }
      });
    }
  }
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question