Kasheftin
@Kasheftin

Проблема с замыканиями в javascript?

Пишу динамическую загрузку javascript-ов. Есть список названий файлов, которые нужно загрузить, и список callback-ов, которые нужно выполнить после загрузки. Типа:

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>


Это значит, что нужно загрузить script1.js, после выполнить callback1, а еще нужно загрузить script2.js и script3.js, и когда оба будут загружены, выполнить callback23.



Пробегаю в цикле по всем onload_js и гружу скрипты через jquery метод $.getScript. Проблема в том, что не знаю, как правильно сделать замыкание внутри callback-а метода $.getScript.



Типа:

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>




Это без замыкания. И понятно, что параметр i внутрь безымянной функции не передается. И все не работает, потому как callback-и вызываются в том порядке как им вздумается. Но написать

$.getCode(onload_js[i]["src"][j],function(i,j) {<br>


нельзя, потому что тогда в i,j приходят переменные из ajax-ответа getCode (т.е. статус ответа и содержание файла). Если же обернуть безымянную функцию в скобки и вызвать call(i,j), то параметры i,j передаются правильно, но сами скрипты не грузятся (callback1 и callback23 не определены).



Что делать?
  • Вопрос задан
  • 3248 просмотров
Пригласить эксперта
Ответы на вопрос 7
taliban
@taliban
php программист
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) )

Код пишу по памяти, но принцип, думаю, поймете, по крайней мере будете знать какой коллбэк вызвался
Ответ написан
pxx
@pxx
В доке про $.getScript написано:
This is a shorthand Ajax function, which is equivalent to:
$.ajax({
url: url,
dataType: 'script',
success: success
});

А в свою очередь в доке про $.ajax есть параметр context:
This object will be made the context of all Ajax-related callbacks

Таким образом можно попробовать сделать так:
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"]();
}
);
}
}


Писал на коленке, ибо воссоздавать ваш пример будет долго, но надеюсь, что должно взлететь.
Ответ написан
kashey
@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();
}
}
}

что мешает сделать просто по другому?
Ответ написан
@Demetros
Если я правильно понял и вам нужно передать текущее значение i, то

(function(i) {
  onload_js[i]["callback"]();
})(i);
Ответ написан
Комментировать
@Demetros
точнее

(function(i) {
    $.getScript(onload_js[i]["src"][j],function() {
      if (//Здесь проверка что все остальные скрипты загружены тоже)
        onload_js[i]["callback"]();
    }
})(i);
Ответ написан
Комментировать
pxx
@pxx
Кстати, конструкция for (var i in onload_js) — опасная: i, кроме значений [0, 1] будет принимать паразитные названия методов и пропертей объекта Array: $family, each, clean, associate, link, contains, extend, getLast, getRandom, include, combine, erase, empty, flatten, hexToRgb, rgbToHex, toJSON.
Чтобы избежать этого нужна дополнительная оберточная проверка:
for (var i in onload_js) {
if (onload_js.hasOwnProperty(i)) { /* do something */}
}
Ответ написан
mnasyrov
@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();
				}
			});
		}
	}
}
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы