2010-05-10 3 views
6

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

Я вижу ожидаемое поведение в 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> 

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

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

EDIT (10/5/10): Когда я говорю, разобран, я имею в виду выполнить - можно увидеть много преимуществ агрессивного разбора - THx rikh

EDIT (11/5/10): Хорошо, поэтому я собрал тест в соответствии с тем, что указано juandopazo. Однако я добавил комбинацию вещей, включая

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

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

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

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

Изображение 1 - График запроса Lifecycle
Request lifecycle Graph http://dyn-script-load.appspot.com/images/dynScriptGraph.png

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

Chrome Результаты

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

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

Firefox Результаты

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

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

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

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

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

+0

Я поднял это как ошибку в вопросах хромированного регистр - http://code.google.com/p/chromium/issues/detail? id = 46109 – hawkett

ответ

2

Извините за ответ на мой собственный вопрос, но это было некоторое время, и мы придумали решение. Мы пришли к тому, чтобы загрузить 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

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

+0

Это было мое понимание. – hawkett

0

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

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

0

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

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

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

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

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

Майк

EDIT: если они добавляются динамически с JavaScript, я думаю, что они обрабатываются в порядке их добавления времени.

+0

Отлично, это то, чего я ожидал - так что если я вижу сценарии * не *, выполненные в том порядке, в котором они появляются в документе (который также является порядком, в котором они были добавлены вовремя), это будет ошибкой в WebKit? У меня есть четыре вещи, рассказывающих мне, что происходит (1) Фактическая структура DOM, показывающая сценарии в правильном порядке (2) Просмотр нагрузки ресурсов в инструментах dev, показывающих второй скрипт, принимаемый первым (3) Журнал консоли, показывающий порядок добавления сценариев (по времени) и (4) журнал консоли, показывающий первый исполняемый скрипт – hawkett

+0

Возможно, в последней строке A.js поместите строку, включающую B.js через «document.write»? –

+0

Основная цель - загрузить скрипты параллельно, но выполнить их в том порядке, в котором они были добавлены. Это работает в Firefox, но не в хром/сафари. Я могу использовать 2-й подход в тесте (см. Править в основном сообщении), чтобы гарантировать правильный порядок выполнения во всех браузерах, но он не является параллельным. Я думаю, что вместо того, чтобы использовать ваш предложенный подход для последовательной загрузки (и, следовательно, для выполнения), я бы пошел с jQuery.append(), поскольку в самих скриптах не требуется дополнительный код. Тем не менее, у меня есть серийная загрузка, работающая прямо сейчас - я ищу параллельное решение для повышения производительности - ура. – hawkett

0

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

+0

Это определенно работает - я нахожусь в стороне от этого, чтобы получить преимущества производительности при загрузке скриптов одновременно :) – hawkett

0

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

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

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

+0

Я посмотрел на структуру DOM для теста и отметил пару вещей - во-первых, скрипты находятся в теле, а не в голове, а второй скрипт указан первым - поэтому, если упорядочение было выполнено, вы ожидаете, что скрипт 2 выполнит первый - хороший тест, хотя было бы хорошо видеть результаты, когда теги скрипта в порядке. ta – hawkett

+0

Справа. Извините, я забыл положить их в голову. Они были в неправильном порядке, потому что я использовал insertBefore() вместо appendChild(). Я изменил его, и результат тот же. Вы должны смотреть на запись какой-то очереди. Запросите модули в разных файлах, которые вызывают методы из глобального объекта. Посмотрите, как работает YUI3. скрипты с вашего кода обычно выглядит следующим образом:. YUI() использовать ('Module1', 'module2', функция (Y) { // сделать что-то }); И начинается каждый модуль: YUI().add ('module1', function (Y) { // добавьте ваши вещи в Y }); – juandopazo

+0

Спасибо за это - у меня нет достаточной репутации, чтобы пометить извините. Просто пытаюсь понять, почему я вижу, как Firefox работает, как ожидалось, в моем сценарии, но не в вашем. Похоже, я, вероятно, неправильно понял свою ситуацию. – hawkett

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