Загрузите и выполните javascript-код SYNCHRONOUSLY

Есть ли способ загрузить и выполнить файл javascript синхронно, как синхронный XMLHttpRequest?

В настоящее время я использую sync XMLHttpRequest, а затем eval для этого, но отладка этого кода очень сложна...

Спасибо за вашу помощь!

Обновление

Я попробовал это сейчас:

test.html

<html>
    <head>
        <script type="text/javascript">
            var s = document.createElement("script");
            s.setAttribute("src","script.js");
            document.head.appendChild(s);
            console.log("done");
        </script>
    </head>
    <body>
    </body>
</html>

script.js

console.log("Hi");

Вывод: сделанный Привет

Таким образом, он не выполнялся синхронно. Любая идея сделать "Привет" сначала?

Обновление 2 Другой пример

test.html(код внутри тега script)

var s = document.createElement("script");
s.setAttribute("src","script.js");
document.head.appendChild(s);
SayHi();

script.js

function SayHi(){
    console.log("hi");
}

Выход: Непринятый ReferenceError: SayHi не определен

Ответ 1

Если вы используете это:

function loadScriptSync (src) {
    var s = document.createElement('script');
    s.src = src;
    s.type = "text/javascript";
    s.async = false;                                 // <-- this is important
    document.getElementsByTagName('head')[0].appendChild(s);
}

Вы можете делать то, что хотите (хотя и разделены в дополнительном файле script)

test.html (код внутри тега script):

loadScriptSync("script.js");
loadScriptSync("sayhi.js"); // you have to put the invocation into another script file

script.js

function SayHi() {
     console.log("hi");
}

sayhi.js

SayHi();

Ответ 2

Все сценарии, загружаемые после готовности DOM, загружаются асинхронно. Единственная причина, по которой браузер загружает их синхронно, это функция write, которая может выводить что-то. Таким образом, вы можете использовать обратный вызов onload элемента script для достижения желаемого.

var s = document.createElement("script");
s.setAttribute("src","script.js");
s.onload = function(){
    console.log('Done');
}
document.head.appendChild(s);

Другой способ - загрузить js файл через XHR и установить код внутри элемента script:

window.onload = function(){
    var req = new XMLHttpRequest();
    req.open('GET', "test.js", false);
    req.onreadystatechange = function(){
        if (req.readyState == 4) {
            var s = document.createElement("script");
            s.appendChild(document.createTextNode(req.responseText));
            document.head.appendChild(s);
        }
    };
    req.send(null);
}

Ответ 3

Из аналогичного вопроса (fooobar.com/questions/10980/...):

<script type="text/javascript">
  document.write('<script type="text/javascript" src="other.js"><\/script>');
</script>

<script type="text/javascript">
  functionFromOther();
</script>

Любой код, вызываемый из document.write 'd script, должен быть в нем <script> или должен находиться в событии window.onload().

Ответ 4

Ваши скрипты выполняются синхронно

ваш код, если он составлен:

1. create script element
2. set its attribute src
3. set its attribute deferred
4. display done...

эта первая часть останавливает выполнение и передает ее на следующий script

5. script executes and displays Hi

Все очень синхронно... В Javascript некоторый код выполняется полностью до тех пор, пока он не выполнится до последней строки или выполнения рук во внутренние системы (например, XHR или таймер).

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

// some code
setTimeout(function(){ alert("I'm second alert"); }, 1);
longExecutionTask();
alert("I'm the first alert");

В приведенном выше коде, даже если setTimeout установлен на выполнение после 1 мс, он не запустится до тех пор, пока код не завершит выполнение, заканчивающееся отображением окна alert. То же самое происходит и в вашем случае. Первая партия кода должна закончить выполнение, прежде чем что-нибудь еще может начать.

Почему вы получаете исключение (в примере 2)

Вы добавили еще один код после того, как я написал свой ответ, поэтому здесь приведена дополнительная информация.

Добавление тега script не приведет к его немедленному выполнению. script Загрузка + выполнение произойдет, когда парсер HTML получит элемент SCRIPT, который вы добавили. Он будет загружать его в этот момент и оценивать/выполнять его содержимое.

  • Парсер HTML начинает анализ вашего документа.
  • HEAD анализируется и его дочерний тег SCRIPT обрабатывается и выполняется. Это выполнение добавляет еще один элемент в тег BODY, который еще не был проанализирован.
  • Parser переходит на BODY и анализирует его содержимое (недавно добавленный тег SCRIPT), который затем загружает script и выполняет его содержимое.

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

Ответ 5

Вы можете синхронизировать асинхронные операции между собой. Создайте рекурсивную функцию для представления цикла и вызовите следующую операцию при предыдущем завершении. Следующая функция импортирует скрипты в соответствии с аналогичной техникой. Он ждет загрузку script, и если ошибка не будет продолжена со следующей. Если возникает ошибка, он вызывает функцию обратного вызова с событием ошибки, а если нет ошибки - вызывает ту же функцию обратного вызова с нулевым значением после загрузки всех скриптов. Он также очищает после себя s.parentNode.removeChild(s).

function importScripts(scripts, callback) {
    if (scripts.length === 0) {
        if (callback !== undefined) {
            callback(null);
        }
    }
    var i = 0, s, r, e, l;
    e = function(event) {
        s.parentNode.removeChild(s);
        if (callback !== undefined) {
            callback(event);
        }
    };
    l = function() {
        s.parentNode.removeChild(s);
        i++;
        if (i < scripts.length) {
            r();
            return;
        }
        if (callback !== undefined) {
            callback(null);
        }
    };
    r = function() {
        s = document.createElement("script");
        s.src = scripts[i];
        s.onerror = e;
        s.onload = l;
        document.head.appendChild(s);
    };
    r();
}