Можно ли доверять script.readyState для определения окончания динамической загрузки скрипта?
Я использую динамическую загрузку скрипта, чтобы уменьшить продолжительность начальной загрузки страницы. Чтобы обеспечить доступность функций и объектов, определенных сценарием, я должен убедиться, что сценарий полностью загружен.
С этой целью я разработал свою собственную библиотеку Javascript и, таким образом, провел довольно много исследований по этому вопросу, изучая, как это делается в разных библиотеках. В ходе обсуждения этой проблемы Кайл Симпсон, автор LABjs, заявил, что:
LABjs (и многие другие загрузчики) устанавливают "onload" и "onreadystatechange" для всех элементов скрипта, зная, что некоторые браузеры будут запускать один, а другие - другой...
Вы можете найти пример этого в текущей версии jQuery на момент написания, 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 срабатывает слишком рано.
Я опубликую свои собственные выводы в ответ на этот вопрос и хотел бы собрать дополнительные доказательства и отзывы сообщества.
5 ответов
В Opera нельзя доверять свойству script.readyState. Например, readyState "загружен" может быть запущен до запуска скрипта в Opera 9.64.
Я выполнил один и тот же тест в 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, и его нельзя устанавливать в других браузерах.
В Firefox, Safari и Chrome вызывается never обработчика onreadystatechange.
Я создал короткий контрольный пример, создав динамический сценарий только с набором обработчиков 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 не требуется.
Я обнаружил, что Internet Explorer (тестирование в 9) НЕ ВСЕГДА готовит ваш скрипт, когда readyState === 'загружен'. Я имел успех, используя этот обработчик событий (в 9, конечно) onactivate. Вытаскивал мои волосы раньше.
В Internet Explorer обработчик onreadystatechange срабатывает, как и ожидалось, после завершения сценария.
Я выполнил тот же тест в 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 всегда "завершен", и он был прежним после обновления нескольких страниц.
Однако, как отметил в этом посте Николас С. Закас, вы также можете наблюдать "загруженный" и "полный" или просто "загруженный" при других обстоятельствах.
Подобные результаты в Chrome.
Не берут уже...
Просто onload и onerror.