Является ли 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/

Думаю, было бы интересно попробовать это с "принудительной", отложенной доставкой скриптов...

  1. добавил два доступных скрипта от Google
  2. добавлен delayjs.php в качестве второго элемента массива. delayjs.php спит в течение 5 секунд, прежде чем доставить пустой объект js.
  3. добавлен обратный вызов, который "проверяет" наличие ожидаемых объектов из файлов сценария.
  4. добавлено несколько 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 и запустите скрипт в каждом из них, каждый из которых вызывает функцию в главном кадре, которая должна иметь смысл результатов этих функций.

Другие вопросы по тегам