Выполнение JavaScript, загруженного через вставку DOM - PullRequest
6 голосов
/ 24 сентября 2011

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

http://friendlybit.com/js/lazy-loading-asyncronous-javascript

Проблема, которую я имею, заключается вкод в моем динамически загружаемом файле javascript просто не выполняется.Извините, если это кажется дублирующим вопросом, но я потратил часы на поиск и пробовал немного разные методы, и я прочитал множество постов, в том числе следующие вопросы stackoverflow:

но я все еще изо всех сил пытаюсь сделать эту работу, поэтому я надеялся, что если я задам вопрос напрямую, кто-то здесь сможет мне помочь!

I 'В настоящее время мы получили следующее в качестве базового теста;очевидно, в моем реальном сценарии происходит гораздо больше, но мне просто нужно понять, что здесь происходит (или, собственно, чего не происходит).

Так что в моем кодовом файле "test.js" я простоиметь:

run_test = function () {
    alert('hello from test');
};

затем на странице, которая у меня есть:

(function () {
     load_test = function () {
        var t = document.getElementsByTagName('script')[0];
        var s = document.createElement('script');
        s.type = 'text/javscript';
        s.async = true;
        s.src = 'test.js';

        s.onload = s.readystatechange = function () {
            if (run_test) run_test();

            s.onload = null;
            s.onreadystatechange = null;
        };

        t.parentNode.insertBefore(s, t);
    };

    load_test();
})();

Я уже пробовал несколько вариантов этого - я пытался удалить "s.async = true" просточтобы увидеть, если это имеет значение, но это не так.Первоначально у меня было следующее вместо «load_test ();», как предложено в первом посте, о котором я говорил:

window.attachEvent ? window.attachEvent('onload', load_test) : window.addEventListener('load', load_test, false);

, но результат всегда один и тот же, я никогда не вижу сообщения «привет из теста»,На самом деле, я даже могу поместить оповещения в функцию load_test - если я поставлю оповещение непосредственно перед строкой «s.onload = s.readystatechange ..», я вижу это сообщение, но оповещение внутри этой функции onload никогда не появляется.Таким образом, может показаться, что динамически добавляемый сценарий onload никогда не срабатывает.

Кстати, в стороне - может или не может иметь значение, но я обычно тестирую в Firefox, и если я смотрю на HTML в Firebug, я вижускрипт test.js был загружен, но если я разверну этот узел, я просто увижу сообщение «Перезагрузить страницу, чтобы получить источник для ...».Не имеет значения, сколько раз я перезагружаю страницу, я не вижу код.Я пробовал тестировать в других браузерах с такими же результатами.

Не могу не почувствовать, что я упускаю что-то фундаментальное здесь;любая помощь будет очень признателен!

Пит


Спасибо всем за ввод.

@ zzzzBov, спасибо за пример, хотя я не уверенЯ до сих пор полностью понимаю - я думал, что «onload» сработает один раз после того, как скрипт завершит загрузку, точно так же, как и присоединение кода к событию onload на странице.Мое понимание «onreadystatechange» заключалось в том, что это было просто для того, чтобы поймать одно и то же в IE.

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

Что касается пути test.js, я пропустил этот путь только для упрощения примера.Мой путь к сценарию определенно правильный;Через firebug я вижу, что скрипт действительно добавлен (в голову).

Моя проблема заключалась в том, что после загрузки скрипта он просто не запускался, но я думаю, что у меня действительно возникли некоторые проблемы с кэшированием, поскольку с тех пор я получил эту работу, используя шаблон, описанный в первой ссылке, которую я разместил выше(здесь снова для хорошей меры: http://friendlybit.com/js/lazy-loading-asyncronous-javascript/).

Итак, мой код выглядит примерно так:

(function () {
    var addscript = function () {
        var h = document.getElementsByTagName('head')[0],
            s = document.createElement('script');
        s.type = "text/javascript";
        s.async = true;
        s.src = "myscript.js";
        h.appendChild(s);
    };
    window.attachEvent ? window.attachEvent('onload', addscript) : 
        window.addEventListener('load', addscript, false);
})();

Если вы проверяете комментарии к этому посту, я думаю, что где-то объясняется, почемухорошая идея по-прежнему включать «s.async = true», даже если в этом случае скрипт присоединяется к событию onload окна.

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

Еще раз спасибо за помощь.

Пит

1 Ответ

4 голосов
/ 24 сентября 2011

У вас есть несколько проблем с вашим сценарием. Вот тот, который должен работать.

function loadScript(src, callback)
{
  var s, r;
  r = false;
  s = document.createElement('script');
  s.type = 'text/javascript';
  s.src = src;
  s.onload = s.onreadystatechange = function() {
    //console.log( this.readyState ); //uncomment this line to see which ready states are called.
    if ( !r && (!this.readyState || this.readyState == 'complete') )
    {
      r = true;
      callback();
    }
  };
  document.body.appendChild(s);
}

Проблема с вашей load_test функцией заключается в том, что она вызовет run_test() перед выполнением нового скрипта. Ваш скрипт удалит обратные вызовы событий onload и onreadystatechange при первом событии onreadystatechange, которое обычно loading.

Кроме того, async не требуется, поскольку вновь добавленный скрипт будет вставлен в конце document.body, где бы это ни было. Если вы хотите загрузить скрипт после остальной части страницы, дождитесь загрузки остальной части страницы (body.onload или document.onreadystatechange), прежде чем вызывать loadScript.

Самая большая проблема с вашим скриптом звучит так: test.js не существует на пути, по которому он вызывается. Убедитесь, что добавление <script type="text/javascript" src="test.js"></script> inline действительно работает.

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