Можно ли «поточить» Javascript и сохранить доступ к интерфейсу? - PullRequest
9 голосов
/ 27 октября 2011

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

Например:

function StartStuff() {
    StartThreadedCode();
    // do more work and update the UI while StartThreadedCode() does its work
}

function StartThreadedCode() {
    // do stuff (do work and update the UI)
}

Возможно ли это?

Ответы [ 3 ]

17 голосов
/ 27 октября 2011

Существует два основных способа достижения «многопоточности» в Javascript. Первый способ - это кросс-браузерное решение, которое также работает в старых браузерах, но является более сложным в реализации.

Идея заключается в том, что вы даете пользовательскому интерфейсу время на обновление каждый раз через некоторое время. Поскольку в Javascript нет функции синхронного сна, единственный способ добиться этого - использовать setTimeout (или setInterval с немного более сложной логикой), чтобы задерживать выполнение каждого цикла ваших сложных вычислений. Это дало бы браузеру некоторое время для обновления пользовательского интерфейса между циклами, давая визуальный эффект нескольких вещей, происходящих одновременно. Нескольких мс должно быть более чем достаточно, чтобы пользовательский интерфейс отражал последние изменения.

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

Второй вариант - использовать веб-работников, которые в основном являются сценариями Javascript, работающими независимо в фоновом режиме, как поток. Это намного проще в реализации, вам нужно только беспокоиться об обмене сообщениями между основным кодом и фоновыми рабочими, поэтому ваше приложение не будет затронуто так сильно. Вы можете прочитать об их использовании по ссылке, размещенной Mic https://developer.mozilla.org/en/Using_web_workers. Самым большим недостатком веб-работников является их поддержка браузерами, которую вы можете увидеть по адресу http://caniuse.com/#search=worker Нет никакого возможного обходного пути для IE <9 или мобильные браузеры, которые действительно имитируют эффект, поэтому с этими браузерами вы мало что можете сделать, но, опять же, преимущества современных браузеров могут перевесить плохую поддержку IE. Это, конечно, зависит от вашей заявки. </p>

Редактировать: Я не уверен, достаточно ли я объяснил первую концепцию, поэтому я решил добавить небольшой пример. Следующий код функционально эквивалентен:

for (var counter = 0; counter < 10; counter++) {
  console.log(counter);
}

Но вместо записи 0-9 в быстрой последовательности он задерживается на 1 с перед выполнением следующей итерации цикла.

var counter = 0;

// A single iteration of your calculation function
// log the current value of counter as an example
// then wait before doing the next iteration
function printCounter() {
  console.log(counter);
  counter++;
  if (counter < 10)
    setTimeout(printCounter, 1000);
}

// Start the loop
printCounter();
1 голос
/ 22 сентября 2017

По состоянию на 2009 г. (FF 3.5 / Gecko 1.9.1) был добавлен новый веб-API, который называется Web Workers .Он также работает в Chrome 4+, Opera 10.6+ и IE10 +.

Рабочий - это в основном фоновый поток, который выполняется в отдельном процессе.

Связь между главным процессом (например, основным потоком вашего пользовательского интерфейса) и подчиненным процессом (фоновый поток, рабочий) устанавливается с помощью универсальной функции PostMessage / onmessage, где вы можете обмениваться любыми данными.Вы любите между двумя сторонами.

Стоит отметить, что каждый отдельный работник назначен на другое ядро.Например, создав 4 разных рабочих (которые выполняют длительные вычисления) на четырехъядерном процессоре, вы увидите все 4 ядра ЦП, например, 100%, в то время как основной сценарий по-прежнему находится в режиме ожидания и, таким образом, реагирует на события пользовательского интерфейса.(посмотрите на этот пример ).

Базовый пример:

main-script.js

if ("function" !== typeof window.Worker) {
  throw "Your browser doesn't support Web Workers";
}
var thread = new Worker("background-thread.js");
thread.onmessage = function(e) {
  console.log("[A] : I received a " + e.data + " :-P");
};
thread.onerror = function(e) {
  console.log(e);
};

console.log("[A] : I'm sending a PING :-)");
thread.postMessage("PING");

background-thread.js

onmessage = function(e) {
  console.log("[B] : I receveid a " + e.data + " :-)");
  console.log("[B] : I will respond with a PONG ;-)");
  postMessage("PONG");
};

Приведенный выше пример должен выдать следующий вывод на консоль вашего браузера:

[A]: я отправляюPING: -)

[B]: я получил PING: -)

[B]: я отвечу PONG; -)

[A]:Я получил PONG: -P

Так счастлив пинг-твой фоновый скрипт!

0 голосов
/ 27 октября 2011

Javascript - это однопоточный язык, но вы можете сделать несколько трюков для имитации многопоточности:

http://www.nczonline.net/blog/2009/08/11/timed-array-processing-in-javascript/

http://www.nczonline.net/blog/2011/09/19/script-yielding-with-setimmediate/

http://www.nczonline.net/blog/2011/05/03/better-javascript-animations-with-requestanimationframe/

...