Динамическое дополнение сценария должно быть заказано? - PullRequest
6 голосов
/ 10 мая 2010

Я добавляю некоторые теги <script> динамически в элемент head после загрузки страницы. Я понимаю, что скрипты загружаются асинхронно, но можно ли ожидать, что они будут проанализированы в порядке их добавления?

Я вижу ожидаемое поведение в Firefox, но не в Safari или Chrome. Глядя на документ в инструментах разработчика Chrome и Firebug, оба показывают следующее -

<html>
  <head>
    ...
    <script type="text/javascript" src="A.js"></script>
    <script type="text/javascript" src="B.js"></script>
  </head>
  ...
</html>

Однако, глядя на представление загрузки ресурсов, кажется, что chrome выполняет синтаксический анализ того, что возвращается с сервера первым, в то время как firebug всегда загружает их в том порядке, в котором были добавлены теги сценария, даже когда B возвращается с сервера первым.

Стоит ли ожидать, что Chrome / Safari проанализирует файлы в указанном порядке? Использование бета-версии Chrome 5.0.375.29 на OS X 10.6.3

РЕДАКТИРОВАТЬ (10/5/10): Когда я говорю "синтаксический анализ", я имею в виду выполнить - может увидеть много преимуществ агрессивного анализа - thx rikh

РЕДАКТИРОВАТЬ (11/5/10): Хорошо, так что я собрал тест по тому же принципу, что и Джандопазо ниже. Однако я добавил комбинацию вещей, в том числе

  1. Добавление элемента script к голове напрямую с помощью javascript. (Тесты A -> D)
  2. Добавление элемента script в заголовок с помощью метода append () jquery. (Тесты E -> H)
  3. 'Загрузка' скрипта с помощью метода getScript () jquery. (Тесты I -> L)

Я также попробовал все комбинации атрибутов 'async' и 'defer' в тегах сценария.

Вы можете получить доступ к тесту здесь - http://dyn -script-load.appspot.com / и просмотреть исходный код, чтобы увидеть, как он работает. Загруженные скрипты просто вызывают функцию update ().

Первое, на что нужно обратить внимание, - это то, что только 1-й и 3-й методы выше работают параллельно - 2-й выполняет запросы последовательно. Вы можете увидеть график этого здесь -

Изображение 1 - график жизненного цикла запроса
Запрос графика жизненного цикла http://dyn -script-load.appspot.com / images / dynScriptGraph.png

Также интересно, что подход jquery append () также блокирует вызовы getScript () - вы можете видеть, что ни один из них не выполняется до тех пор, пока все вызовы append () не будут завершены, а затем все они будут выполняться параллельно. В заключение отметим, что метод jQuery append (), по-видимому, удаляет теги сценария из заголовка документа после их выполнения. Только первый метод оставляет теги скрипта в документе.

Результаты Chrome

В результате Chrome всегда выполняет первый возвращаемый скрипт, независимо от теста. Это означает, что все тесты «провалились», кроме метода jQuery append ().

Изображение 2 - Результаты Chrome 5.0.375.29 beta
Результаты Chrome http://dyn -script-load.appspot.com / images / chromeDynScript.png

Результаты Firefox

Однако в Firefox, похоже, что если используется первый метод, а async имеет значение false (то есть не установлено), то сценарии будут надежно выполняться по порядку.

Изображение 3 - Результаты FF 3.6.3
Результаты FF http://dyn -script-load.appspot.com / images / ffDynScript.png

Обратите внимание, что Safari, похоже, дает различные результаты так же, как и Chrome, что имеет смысл.

Кроме того, у меня есть задержка в 500 мс для медленного сценария, просто чтобы уменьшить время начала и окончания. Возможно, вам придется обновить пару раз, чтобы Chrome и Safari перестали работать во всех случаях.

Мне кажется, что без способа сделать это мы не воспользуемся возможностью параллельного извлечения данных, и нет никаких причин, почему мы не должны этого делать (как показывает Firefox).

Ответы [ 6 ]

2 голосов
/ 30 июля 2010

Извините за ответ на мой собственный вопрос, но прошло некоторое время, и мы нашли решение. Мы пришли к тому, чтобы одновременно загружать javascript как текст, содержащийся в объекте json, а затем использовать eval (), как только они были загружены, чтобы выполнить их в правильном порядке. Параллельная загрузка плюс заказное исполнение. В зависимости от вашего варианта использования вам может не понадобиться JSON. Грубо, вот код, который показывает, что мы сделали -

// 'requests' is an array of url's to javascript resources
var loadCounter = requests.length;
var results = {};

for(var i = 0; i < requests.length; i++) {
   $.getJSON(requests[i], function(result) {
      results[result.id] = result;
      ...
      if(--loadCounter == 0) finish();
   });
}

function finish() {
  // This is not ordered - modify the algorithm to reflect the order you want
  for(var resultId in results) eval(results[resultId].jsString);
}
0 голосов
/ 10 мая 2010

Я исследовал это, работая над небольшой библиотекой, которая динамически загружает модули, например YUI 3. Я создал небольшой тест, который загружает два скрипта, которые просто вставляют содержимое в div. Один из них - это обычный файл JS, а другой - файл PHP, ожидающий выполнения в течение 3 секунд.

http://www.juandopazo.com.ar/tests/asyn-script-test.html

Как видите, сценарии выполняются по завершении загрузки, а не в том порядке, в котором вы добавляете их в DOM в каждом браузере.

0 голосов
/ 10 мая 2010

Вы можете загрузить b.js из a.js , чтобы быть на 100% уверенным ... хотя я бы сам хотел получить окончательный ответ на этот вопрос, особенно с sync ajax загрузка скриптов.

0 голосов
/ 10 мая 2010

Порядок загрузки и порядок выполнения не одно и то же. На вашей странице, даже если B.js загружается первым, движок браузера будет ждать, пока A.js продолжит обработку страницы.

Сценарии определенно обрабатываются не только в том порядке, в котором они появились в документе, но и в том месте, где они появились.

Представьте, что если бы это было не так, было бы много ошибок, если бы ваш маленький скрипт, использующий jQuery, был загружен и обработан до библиотеки jQuery.

Кроме того, когда вы делаете «document.write» в js-файле, он появляется там, где был объявлен скрипт. Вы также не можете получить доступ к объектам DOM, которые появляются после объявления скрипта.

Вот почему есть рекомендации размещать скрипты в самом низу страницы, чтобы предотвратить их слишком быстрое выполнение и уменьшить «воспринимаемое время загрузки» страницы, потому что движок рендеринга браузера останавливается, как только скрипт обрабатывается.

Mike

РЕДАКТИРОВАТЬ: если они добавляются динамически с Javascript, я думаю, что они обрабатываются в порядке, они были добавлены во времени.

0 голосов
/ 10 мая 2010

Нет, вы не можете ожидать, что все браузеры будут откладывать выполнение обоих скриптов до тех пор, пока оба не будут загружены (** особенно, когда вы добавляете их динамически).

Если вы хотите выполнить код в B.js только после загрузки A.js, тогда лучше всего добавить onload обратный вызов к A.js, который устанавливает переменную, и еще один к B.js, который проверяет на Посмотрите, была ли установлена ​​эта переменная, тогда она выполнит необходимую функцию в B.js, если она имеет (и если A.js не загружена, она запускает таймер, который периодически проверяет, пока не загрузится).

0 голосов
/ 10 мая 2010

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

...