Можно ли доверять script.readyState для определения окончания динамической загрузки скрипта? - PullRequest
30 голосов
/ 18 декабря 2009

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

С этой целью я разработал свою собственную библиотеку 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 ]

8 голосов
/ 18 декабря 2009

В 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 и не устанавливать в других браузерах.

3 голосов
/ 18 декабря 2009

В 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 не требуется.

1 голос
/ 23 марта 2012

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

1 голос
/ 18 декабря 2009

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

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

0 голосов
/ 12 июля 2012

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

Не берет уже ...

Просто загрузка и ошибка.

...