2009-12-18 1 views
25

Я использую динамическую загрузку сценария, чтобы уменьшить длительность начальной загрузки страницы. Чтобы обеспечить доступность функций и объектов, определенных скриптом, мне нужно убедиться, что сценарий полностью загружен.Может ли script.readyState доверять обнаружение конца загрузки динамического скрипта?

С этой целью я разработал my own Javascript library, и поэтому провел довольно много исследований по этому вопросу, изучив, как это делается в разных библиотеках. В ходе обсуждения в связи с этим вопросом, Кайл Симпсон, автор LABjs, заявил, что:

LABjs (и многие другие погрузчики) установить как «OnLoad» и «onreadystatechange» всех элементов сценария, зная что некоторые браузеры будут срабатывать один, а некоторые будет стрелять другой ...

Вы можете найти пример в the current version of jQuery as of this writing, v1.3.2:

// Attach handlers for all browsers 
script.onload = script.onreadystatechange = function(){ 
    if (!done && (!this.readyState || 
    this.readyState == "loaded" || this.readyState == "complete")) { 
     done = true; 
     success(); 
     complete(); 

     // Handle memory leak in IE 
     script.onload = script.onreadystatechange = null; 
     head.removeChild(script); 
    } 
}; 

Это современное состояние, но во время анализа странного поведения в Opera 9.64 я пришел к выводу, что, используя эту технику, обратный вызов onload был запущен слишком рано.

Я отправлю свои собственные выводы в ответ на этот вопрос и хотел бы получить дополнительные данные и отзывы от сообщества.

+0

Кто-нибудь найдет текущий код в ветке jQuery 1.x? Похоже, они прекратили использование '.onreadystatechange' и' .onload' и заменили их обещаниями? [Clicky] (https://github.com/jquery/jquery/blob/1.x-master/src/ajax.js) – Campbeln

ответ

7

В Opera нельзя использовать свойство script.readyState. Например, готовый ReadyState может быть запущен до запуска скрипта в Opera 9.64.

Я исполнил the same test в Opera 9.64 и Opera 10 с разными результатами.

В Opera 9.64 обработчик onreadystatechange запускается дважды, один раз до и один раз после запуска скрипта. ReadyState свойство «загружается» в обоих случаях, что означает, что это значение не может быть доверенным для обнаружения конца загрузки сценария:

# Fri Dec 18 2009 17:54:43 GMT+0100 
# Opera/9.64 (Windows NT 5.1; U; en) Presto/2.1.1 
Test for script.readyState behavior started 
Added script with onreadystatechange handler 
readystatechange: loaded 
test1.js: Start 
test1.js: Start of closure 
test1.js: End of closure 
readystatechange: loaded 

В Opera 10, обработчик onreadystatechange еще увольняют дважды со значением " загружен», но оба раза после сценария гласил:

# Fri Dec 18 2009 18:09:58 GMT+0100 
# Opera/9.80 (Windows NT 5.1; U; en) Presto/2.2.15 Version/10.10 
Test for script.readyState behavior started 
Added script with onreadystatechange handler 
test1.js: Start 
test1.js: Start of closure 
test1.js: End of closure 
readystatechange: loaded 
readystatechange: loaded 

Эти различные типы поведения показывают, что onreadystatechange не является надежным способом обнаружения конец загрузки скрипта в Opera. Поскольку Opera также поддерживает прослушиватель onload, этот другой механизм следует использовать вместо этого.

Основываясь на результатах этих тестов, onreadystatechange следует использовать только для обнаружения конца загрузки сценария в Internet Explorer, и его нельзя устанавливать в других браузерах.

+0

По крайней мере, вы можете игнорировать первое событие. –

+2

@ Justin Johnson, который кажется неудобным, вы считаете «загруженные» события, но только в Opera? –

3

В Firefox, Safari и Chrome вызывается обработчик onreadystatechange nevers.

Я создал короткий тестовый случай, создавая динамический сценарий только с набором обработчика onreadystatechange:

<script type="text/javascript" language="javascript"> 
bezen.log.info(new Date(),true); 
bezen.log.info(navigator.userAgent,true); 

// Activate logs 
bezen.log.on(); 
bezen.log.info('Test for script.readyState behavior started'); 

var script = document.createElement('script'); 
script.src = 'test1.js'; 
script.onreadystatechange = function(){ 
    bezen.log.info('readystatechange: '+script.readyState); 
}; 
document.body.appendChild(script); 
bezen.log.info('Added script with onreadystatechange handler'); 
</script> 

я выполнил тест на локальный файл в Firefox 2, Firefox 3, Firefox 3.5, Safari 3, Safari 4 и Chrome 3, и получили аналогичные результаты (здесь журналы, записанные в FF 3.5):

Fri Dec 18 2009 17:53:58 GMT+0100 
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 
Test for script.readyState behavior started 
Added script with onreadystatechange handler 
test1.js: Start 
test1.js: Start of closure 
test1.js: End of closure 

onreadystatechange никогда не вызывается. В этих браузерах только приемник onload полезен для обнаружения конца загрузки скрипта, onreadystatechange не требуется.

1

В обозревателе Internet Explorer обработчик onreadystatechange срабатывает, как ожидалось, после окончания сценария.

Я выполнил same test в Internet Explorer 6, Internet Explorer 7 и Internet Explorer 8, с аналогичными результатами в этих трех браузерах (здесь журналы, записанные в Internet Explorer 6):

Fri Dec 18 18:14:51 UTC+0100 2009 
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) 
Test for script.readyState behavior started 
Added script with onreadystatechange handler 
test1.js: Start 
test1.js: Start of closure 
test1.js: End of closure 
readystatechange: complete 

Здесь с тест с использованием локального файла, readyState всегда «завершен», и после обновления нескольких страниц он все тот же.

Однако, как указано в this post by Nicholas C. Zakas, вы также можете наблюдать «загруженные» и «завершенные» или просто «загруженные», при разных обстоятельствах.

1

Я обнаружил, что интернет-исследователь (тестирование в 9) НЕ ВСЕГДА имеет готовый скрипт, когда readyState === «загружен». У меня был успех с использованием этого обработчика событий (в 9 разумеется) onactivate. Вытягивал мои волосы раньше.

0

Аналогичные результаты в Chrome.

Не принимает onready ...

Просто OnLoad и OnError.

Смежные вопросы