Проблема:
Загрузите js-файлы асинхронно, затем проверьте, загружен ли dom, перед выполнением обратного вызова для загрузки файлов.
edit: Мы не используем jQuery; мы используем Prototype.
edit: добавил больше комментариев к примеру кода.
Привет, ребята,
Я пытаюсь загрузить все мои js-файлы асинхронно, чтобы они не блокировали остальную часть страницы. Но когда скрипты загружаются и вызывается обратный вызов, мне нужно знать, был ли загружен DOM или нет, поэтому я знаю, как структурировать обратный вызов. Смотрите ниже:
//load asynchronously
(function(){
var e = document.createElement('script');
e.type = "text/javascript";
e.async = true;
e.src = srcstr;
// a little magic to make the callback happen
if(navigator.userAgent.indexOf("Opera")){
e.text = "initPage();";
}else if(navigator.userAgent.indexOf("MSIE")){
e.onreadystatechange = initPage;
}else{
e.innerHTML = "initPage();";
}
// attach the file to the document
document.getElementsByTagName('head')[0].appendChild(e);
})();
initPageHelper = function(){
//requires DOM be loaded
}
initPage = function(){
if(domLoaded){ // if dom is already loaded, just call the function
initPageHelper();
}else{ //if dom is not loaded, attach the function to be run when it does load
document.observe("dom:loaded", initPageHelper);
}
}
Обратный вызов вызывается должным образом из-за некоторой магии за кулисами, о которой вы можете узнать из этого разговора Google: http://www.youtube.com/watch?v=52gL93S3usU&feature=related
Какой самый простой кросс-браузерный метод для запроса, загрузился ли DOM уже?
EDIT
Вот полное решение, которое я выбрал.
Я включил прототип и загрузчик асинхронных скриптов, используя обычный метод. С прототипом жизнь намного проще, поэтому я готов заблокировать этот сценарий.
<script type="text/javascript" src="prototype/prototype.js"></script>
<script type="text/javascript" src="asyncLoader.js"></script>
И фактически, в своем коде я минимизировал два файла выше и соединил их в один файл, чтобы минимизировать время передачи и запросы http.
Затем я определяю, что я хочу запустить при загрузке DOM, и затем вызываю функцию для загрузки других сценариев.
<script type="text/javascript">
initPage = function(){
...
}
</script>
<script type="text/javascript">
loadScriptAsync("scriptaculous/scriptaculous.js", initPage);
loadScriptAsync("scriptaculous/effects.js", initPage);
loadScriptAsync("scriptaculous/controls.js", initPage);
...
loadScriptAsync("mypage.js", initPage);
</script>
Аналогично, вышеприведенные запросы фактически сжимаются в один httpRequest с использованием минификатора. Они оставлены отдельно для удобства чтения. Внизу этого поста есть фрагмент, показывающий, как выглядит код с минификатором.
Код для asyncLoader.js следующий:
/**
* Allows you to load js files asynchronously, with a callback that can be
* called immediately after the script loads, OR after the script loads and
* after the DOM is loaded.
*
* Prototype.js must be loaded first.
*
* For best results, create a regular script tag that calls a minified, combined
* file that contains Prototype.js, and this file. Then all subsequent scripts
* should be loaded using this function.
*
*/
var onload_queue = [];
var dom_loaded = false;
function loadScriptAsync(src, callback, run_immediately) {
var script = document.createElement('script');
script.type = "text/javascript";
script.async = true;
script.src = src;
if("undefined" != typeof callback){
script.onload = function() {
if (dom_loaded || run_immediately)
callback();
else
onload_queue.push(callback);
// clean up for IE and Opera
script.onload = null;
script.onreadystatechange = null;
};
script.onreadystatechange = function() {
if (script.readyState == 'complete'){
if (dom_loaded || run_immediately)
callback();
else
onload_queue.push(callback);
// clean up for IE and Opera
script.onload = null;
script.onreadystatechange = null;
}else if(script.readyState == 'loaded'){
eval(script);
if (dom_loaded || run_immediately)
callback();
else
onload_queue.push(callback);
// clean up for IE and Opera
script.onload = null;
script.onreadystatechange = null;
}
};
}
var head = document.getElementsByTagName('head')[0];
head.appendChild(script);
}
document.observe("dom:loaded", function(){
dom_loaded = true;
var len = onload_queue.length;
for (var i = 0; i < len; i++) {
onload_queue[i]();
}
onload_queue = null;
});
Я добавил опцию немедленного запуска скрипта, если у вас есть скрипты, которые не зависят от полной загрузки DOM страницы.
Минимизированные запросы на самом деле выглядят так:
<script type="text/javascript" src="/min/?b=javascript/lib&f=prototype/prototype.js,asyncLoader.js"></script>
<script type="text/javascript"> initPage = function(e){...}</script>
<script type="text/javascript">
srcstr = "/min/?f=<?=implode(',', $js_files)?>";
loadScriptAsync(srcstr, initPage);
</script>
Они используют плагин из: http://code.google.com/p/minify/
Спасибо за помощь !!
-К