Подтвердить что ты не робот

Можно ли доверять script.readyState для обнаружения конца динамической загрузки script?

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

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

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

Вы можете найти пример этого в текущей версии 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 был запущен слишком рано.

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

4b9b3361

Ответ 1

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

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

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

# 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 по-прежнему запускается дважды со значением "загружен", но оба раза после запуска script:

# 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 не является надежным способом обнаружения конца загрузки script в Opera. Поскольку Opera также поддерживает прослушиватель onload, этот другой механизм следует использовать вместо этого.

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

Ответ 2

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

Я создал короткий тестовый пример, создав динамический script только с обработчиком 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 полезен для обнаружения конца загрузки script, onreadystatechange не требуется.

Ответ 3

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

Я выполнил тот же тест в 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 всегда "завершен", и после обновления нескольких страниц он оставался неизменным.

Однако, как отмечено в этот пост Николаса К. Закаса, вы также можете наблюдать "загруженные" и "полные", или просто "загружен", при разных обстоятельствах.

Ответ 4

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

Ответ 5

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

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

Просто загрузите и включите.