Является ли JavaScript многопоточным?
Вот моя проблема - мне нужно динамически загружать несколько скриптов с помощью jQuery.getScript() и выполнять определенный код JavaScript после загрузки всех скриптов, поэтому я планировал сделать что-то вроде этого:
function GetScripts(scripts, callback)
{
var len = scripts.length
for (var i in scripts)
{
jQuery.getScript(scripts[i], function()
{
len --;
// executing callback function if this is the last script that loaded
if (len == 0)
callback()
})
}
}
Это будет работать надежно только в том случае, если мы предположим, что события script.onload для каждого скрипта запускаются и выполняются последовательно и синхронно, поэтому никогда не будет ситуации, когда два или более обработчика событий пройдут проверку на наличие (len == 0) и выполнят метод обратного вызова.
Итак, мой вопрос - правильно ли это предположение, и если нет, то как достичь того, что я пытаюсь сделать?
9 ответов
Нет, JavaScript не многопоточный. Это зависит от событий, и вы увидите, что вы предполагаете, что события запускаются последовательно (если они загружаются последовательно). Ваша текущая реализация кажется правильной. Я считаю, что JQuery .getScript()
вводит новый <script>
тег, который также должен заставить их загружаться в правильном порядке.
В настоящее время JavaScript не является многопоточным, но в ближайшем будущем все изменится. В HTML5 появилась новая вещь под названием Worker. Это позволяет вам делать некоторую работу в фоновом режиме.
Но в настоящее время это поддерживается не всеми браузерами.
Спецификация JavaScript (ECMAScript) не определяет какие-либо механизмы потоков или синхронизации.
Более того, механизмы JavaScript в наших браузерах являются преднамеренно однопоточными, отчасти потому, что одновременная работа нескольких потоков пользовательского интерфейса может открыть огромную кучу червей. Так что ваше предположение и реализация верны.
В качестве пояснения Anthony Forloney сослался на тот факт, что любой поставщик JavaScriptengine может добавить функции потоков и синхронизации, или поставщик может позволить пользователям самим реализовать эти функции, как описано в этой статье: Многопоточный JavaScript?
JavaScript абсолютно не многопоточный - у вас есть гарантия, что любой используемый вами обработчик не будет прерван другим событием. Любые другие события, такие как щелчки мышью, XMLHttpRequest, возвращаются, а таймеры помещаются в очередь во время выполнения вашего кода и запускаются одно за другим.
Нет, все браузеры дают вам только один поток для JavaScript.
Для ясности, реализация JS в браузере не многопоточная.
Язык JS может быть многопоточным.
Вопрос здесь не применим, однако.
Что применимо, так это то, что getScript() является асинхронным (возвращает немедленно и получает в очереди), однако, браузер выполнит DOM с подключением <script>
содержимое последовательно, так что ваш зависимый код JS будет видеть их загруженными последовательно. Это функция браузера, которая не зависит от потоков JS или вызова getScript().
Если getScript() извлекает сценарии с помощью xmlHTTPRequest, setTimeout(), websockets или любого другого асинхронного вызова, то ваши сценарии не будут гарантированно выполняться по порядку. Однако ваш обратный вызов будет по-прежнему вызываться после выполнения всех сценариев, поскольку контекст выполнения вашей переменной 'len' находится в замыкании, которое сохраняет свой контекст посредством асинхронных вызовов вашей функции.
JS в целом однопоточный. Однако веб-работники HTML5 вводят многопоточность. Узнайте больше на http://www.html5rocks.com/en/tutorials/workers/basics/
Думаю, было бы интересно попробовать это с "принудительной", отложенной доставкой скриптов...
- добавил два доступных скрипта от Google
- добавлен delayjs.php в качестве второго элемента массива. delayjs.php спит в течение 5 секунд, прежде чем доставить пустой объект js.
- добавлен обратный вызов, который "проверяет" наличие ожидаемых объектов из файлов сценария.
- добавлено несколько js-команд, которые выполняются в строке после вызова GetScripts(), чтобы "проверить" последовательные js-команды.
Результат с загрузкой скрипта, как и ожидалось; обратный вызов срабатывает только после загрузки последнего скрипта. Что меня удивило, так это то, что команды js, которые последовали за вызовом GetScripts(), сработали без необходимости ждать загрузки последнего скрипта. У меня сложилось впечатление, что никакие команды js не будут выполняться, пока браузер ожидает загрузки сценария js...
var scripts = [];
scripts.push('http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js');
scripts.push('http://localhost/delayjs.php');
scripts.push('http://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.3/scriptaculous.js');
function logem() {
console.log(typeof Prototype);
console.log(typeof Scriptaculous);
console.log(typeof delayedjs);
}
GetScripts( scripts, logem );
console.log('Try to do something before GetScripts finishes.\n');
$('#testdiv').text('test content');
<?php
sleep(5);
echo 'var delayedjs = {};';
Вероятно, вы можете получить какую-то многопоточность, если создадите несколько кадров в документе HTML и запустите скрипт в каждом из них, каждый из которых вызывает функцию в главном кадре, которая должна иметь смысл результатов этих функций.