JavaScript: Как загрузить JS асинхронно? - PullRequest
8 голосов
/ 10 мая 2010

На моем веб-сайте я пытаюсь выполнить максимально быструю загрузку страницы.

Я заметил, что мой JavaScript не загружается асинхронно. Изображение связано ниже.

альтернативный текст http://img249.imageshack.us/img249/2452/jsasynch2.png

Мой веб-сайт работает так, что ему нужно загрузить два внешних файла JavaScript:

  • Google Maps v3 JavaScript и
  • JQuery JavaScript

Затем у меня есть встроенный JavaScript в HTML, который не может быть выполнен до тех пор, пока эти два файла не будут загружены.

Как только он загружает эти внешние файлы javascript, он затем и только тогда может динамически отображать страницу. Причина, по которой моя страница не может быть загружена до тех пор, пока не будут загружены Google Maps и JQuery, заключается в том, что - моя страница, основанная на геолокации (с использованием Gmaps) пользователя, будет затем отображать страницу в зависимости от того, где они расположены (например, Нью-Йорк Сан-Франциско и др.) То есть два человека в разных городах, просматривающих мой сайт, увидят разные страницы.

Вопрос : Как получить асинхронную загрузку файлов JavaScript, чтобы общее время загрузки страницы было самым быстрым?

UPDATE

Если бы я каким-то образом загружал Google-карты и JQuery асинхронно, как бы я создавал событие, которое сработало бы один раз , когда Google-карты и JQuery загружались, поскольку моя страница сильно зависела на эти файлы для выполнения.

ОБНОВЛЕНИЕ 2

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

Ответы [ 8 ]

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

Загрузка HTTP обычно ограничена браузерами двумя одновременными загрузками на домен . Вот почему некоторые сайты имеют динамический контент на www.domain.tla и изображениях и javascript на static.domain.tla.

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

Стандартным решением является перемещение сценариев вниз страницы, но есть обходной путь, который может или не может работать для вас: Вставьте элемент DOM сценария , используя Javascript .

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

Кто-то попросил меня прокомментировать эту тему, но это было до того, как @lonut опубликовал ответ. Код @ lonut - очень хорошее решение, но у меня есть несколько комментариев (критических и не очень):

Во-первых, код @ lonut предполагает, что сценарии НЕ имеют зависимостей загрузки от других сценариев. Это немного сложно объяснить, поэтому давайте поработаем с простым примером jquery.min.js и prototype.js. Предположим, у нас есть простая страница, которая просто загружает эти два скрипта, например так:

<script src="jquery.min.js"></script>
<script src="prototype.js"></script>

Помните - на странице больше ничего нет - никакого другого кода JavaScript. Если вы загрузите эту страницу, два скрипта будут загружены, и все в порядке. Теперь, что произойдет, если вы удалите скрипт jquery.min.js? Если вы получаете ошибки из prototype.js, потому что он пытается ссылаться на символы, определенные в jquery.min.js, то prototype.js имеет зависимость загрузки от jquery.min.js - вы не можете загрузить prototype.js, если jquery.min.js не имеет уже был загружен. Если, однако, вы не получите никаких ошибок, тогда два скрипта могут быть загружены в любом порядке, который вы пожелаете. Предполагая, что у вас нет зависимостей загрузки между вашими внешними скриптами, код @ lonut великолепен. Если у вас есть зависимости загрузки - это становится очень сложно, и вы должны прочитать главу 4 в даже более быстрых веб-сайтах.

Во-вторых, одна проблема с кодом @ lonut заключается в том, что некоторые версии Opera будут вызывать loadCallback дважды (один раз из обработчика onload и второй раз из обработчика onreadystatechange). Просто добавьте флаг, чтобы убедиться, что loadCallback вызывается только один раз.

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

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

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

var require = function (scripts, loadCallback) {
    var length        = scripts.length;
    var first         = document.getElementsByTagName("script")[0];
    var parentNode    = first.parentNode;
    var loadedScripts = 0;
    var script;

    for (var i=0; i<length; i++) {
        script = document.createElement("script");
        script.async = true;
        script.type = "text/javascript";
        script.src = scripts[i];

        script.onload = function () {
            loadedScripts++;

            if (loadedScripts === length) {
                loadCallback();
            }
        };

        script.onreadystatechange = function () {
            if (script.readyState === "complete") {
                loadedScripts++;

                if (loadedScripts === length) {
                    loadCallback();
                }
            }
        };

        parentNode.insertBefore(script, first);
    }
};


require([
    "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js",
    "http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js",
    "http://ajax.googleapis.com/ajax/libs/yui/2.7.0/build/yuiloader/yuiloader-min.js"
], function () {
    console.log(jQuery);
    console.log($);
    console.log(YAHOO);
});
2 голосов
/ 26 января 2012

Вот как мне удалось асинхронно загрузить gmaps на мобильный jquery: Во-первых, вы можете загрузить jquery (то есть с помощью функции require , опубликованной выше Ionuț G. Stan) Затем вы можете использовать параметр callback в gmaps для выполнения следующих действий:

<!DOCTYPE html>
<html>  
<body>
 <script type="text/javascript">
      var require = function (scripts, loadCallback) {
      var length        = scripts.length;
      var first         = document.getElementsByTagName("script")[0];
      var parentNode    = first.parentNode;
      var loadedScripts = 0;
      var script;

      for (var i=0; i<length; i++) {
          script = document.createElement("script");
          script.async = true;
          script.type = "text/javascript";
          script.src = scripts[i];

          script.onload = function () {
              loadedScripts++;

              if (loadedScripts === length) {
                  loadCallback();
              }
          };

          script.onreadystatechange = function () {
              if (script.readyState === "complete") {
                  loadedScripts++;

                  if (loadedScripts === length) {
                      loadCallback();
                  }
              }
          };
          parentNode.insertBefore(script, first);
        }
       };

       require([
      "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js",], function () {

         $.ajax({
            type: "GET",
            url: 'http://maps.googleapis.com/maps/api/js?v=3&sensor=false&callback=setMyMap',
            dataType: "script"
         });

       });

      function setMyMap() {


                       console.log('your actions here');



           var coords = new google.maps.LatLng(40.5439532,-3.6441775);
           var mOptions = {
              zoom: 8,
              center: coords,
              mapTypeId: google.maps.MapTypeId.ROADMAP
           }
           var map = new google.maps.Map(document.getElementById("gmap"), mOptions);
      }
 </script>

 <div id="gmap" style="width:299px; height:299px"></div>

</body>

Суть заключается в том, чтобы загрузить jquery async (какой бы метод вы ни выбрали) и в этом обратном вызове выполнить новый асинхронный вызов gmaps с вашим стартовым методом в параметре callback строки сценария gmaps.

Надеюсь, это поможет

2 голосов
/ 11 августа 2010

Динамический загрузчик сценариев LABjs разработан специально для этого типа случаев. Например, вы можете сделать:

$LAB
  .script("googlemaps.js")
  .script("jquery.js")
  .wait(function(){
     // yay, both googlemaps and jquery have been loaded, so do something!
  });

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

$LAB
  .script("jquery.js")
  .wait() // make sure jquery is executed first
  .script("plugin.jquery.js")
  .script("googlemaps.js")
  .wait(function(){
     // all scripts are ready to go!
  });

В любом случае LABjs загрузит все сценарии ("jquery.js", "googlemaps.js" и "plugin.jquery.js") параллельно, по крайней мере, до того момента, когда браузер позволит. Но благодаря разумному использованию .wait () в цепочке, LABjs убедится, что они выполняются в правильном порядке. То есть, если между двумя сценариями в цепочке нет .wait (), каждый из них выполнит как можно скорее (что означает неопределенный порядок между ними). Если между двумя сценариями в цепочке есть .wait (), то первый сценарий выполнит перед вторым сценарием, даже если они загружены параллельно.

1 голос
/ 11 августа 2010

Переместите ваши JavaScript-включения (<script src="...) из элемента HEAD в конец элемента BODY. Обычно все, что находится в HEAD, загружается синхронно, а все, что помещается в BODY, загружается асинхронно. Это более или менее верно для скриптовых включений, однако большинство браузеров в наши дни блокируют все, что находится ниже скрипта, до тех пор, пока он не будет загружен, поэтому лучше всего включать скрипты в нижней части тела.

Вот линия гильдии YUI, которая объясняет это более подробно: http://developer.yahoo.net/blog/archives/2007/07/high_performanc_5.html

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

1 голос
/ 10 мая 2010

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

Итак, вы можете поставить обе карты Google на первое место, ТОГДА JQuery. Тогда в теле вашей страницы где-то:

<script language="Javascript">

    function InitPage() {
       // Do stuff that relies on JQuery and Google, since this script should
       // not execute until both have already loaded.
       }

    $(InitPage);   // this won't execute until JQuery is ready

</script>

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

Вместо этого вы можете хранить JQuery в HEAD, но загружать сценарии Google из функции InitPage (), используя функцию загрузки Javascript JQuery, а не Google JSAPI. Затем начните рендеринг, когда выполняет функция обратного вызова. То же, что и выше, но вместо этого с помощью функции InitPage ():

  function InitPage() {
     $.getScript('Google Maps Javascript URL', function() {
        // Safe to start rendering now
        });
0 голосов
/ 27 мая 2015

Ваша цель будет достигнута с помощью requireJS. RequireJS загружает ресурсы js асинхронно. Это очень простая и полезная библиотека для реализации. Пожалуйста, прочитайте больше здесь. http://requirejs.org/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...