Вопрос

Есть ли способ реализовать многопоточность в JavaScript?

Это было полезно?

Решение

Видеть http://caniuse.com/#search=worker для получения самой актуальной информации о поддержке.

Ниже приводится состояние поддержки примерно в 2009 году.


Слова, которые вы хотите найти в Google: Рабочие потоки JavaScript

Помимо Шестерни сейчас ничего доступного нет, но много разговоров о том, как это реализовать, так что я думаю, посмотрите этот вопрос, поскольку ответ, несомненно, изменится в будущем.

Вот соответствующая документация для Gears: API рабочего пула

У WHATWG есть проект рекомендации для рабочих потоков: Веб-работники

А еще есть Mozilla Рабочие потоки DOM


Обновлять: Июнь 2009 г., текущее состояние поддержки браузерами потоков JavaScript.

Фаерфокс 3.5 есть веб-работники.Несколько демонстраций веб-воркеров, если вы хотите увидеть их в действии:

Плагин Gears также можно установить в Firefox.

Сафари 4, и WebKit ночные клубы есть рабочие потоки:

Хром в него встроен Gears, поэтому он может создавать потоки, хотя для этого требуется запрос подтверждения от пользователя (и он использует другой API для веб-работников, хотя он будет работать в любом браузере с установленным плагином Gears):

  • Демонстрация Google Gears WorkPool (не очень хороший пример, поскольку он работает слишком быстро для тестирования в Chrome и Firefox, хотя IE запускает его достаточно медленно, чтобы увидеть, что он блокирует взаимодействие)

IE8 и IE9 может создавать темы только с установленным плагином Gears

Другие советы

Другой способ реализации многопоточности и асинхронности в JavaScript

До появления HTML5 JavaScript допускал выполнение только одного потока на странице.

Был какой-то хакерский способ имитировать асинхронное выполнение с помощью Урожай, setTimeout(), setInterval(), XMLHttpRequest или обработчики событий (см. в конце этого поста пример с урожай и setTimeout()).

Но благодаря HTML5 мы теперь можем использовать рабочие потоки для распараллеливания выполнения функций.Вот пример использования.


Реальная многопоточность

Многопоточность:Рабочие потоки JavaScript

HTML5 представили веб-рабочие потоки (см.: совместимость браузеров)
Примечание:IE9 и более ранние версии его не поддерживают.

Эти рабочие потоки представляют собой потоки JavaScript, которые работают в фоновом режиме, не влияя на производительность страницы.Для получения дополнительной информации о Веб-работник прочитайте документацию или этот урок.

Вот простой пример с тремя потоками Web Worker, которые считают MAX_VALUE и показывают текущее вычисленное значение на нашей странице:

//As a worker normally take another JavaScript file to execute we convert the function in an URL: http://stackoverflow.com/a/16799132/2576706
function getScriptPath(foo){ return window.URL.createObjectURL(new Blob([foo.toString().match(/^\s*function\s*\(\s*\)\s*\{(([\s\S](?!\}$))*[\s\S])/)[1]],{type:'text/javascript'})); }

var MAX_VALUE = 10000;

/*
 *	Here are the workers
 */
//Worker 1
var worker1 = new Worker(getScriptPath(function(){
    self.addEventListener('message', function(e) {
        var value = 0;
        while(value <= e.data){
            self.postMessage(value);
            value++;
        }
    }, false);
}));
//We add a listener to the worker to get the response and show it in the page
worker1.addEventListener('message', function(e) {
  document.getElementById("result1").innerHTML = e.data;
}, false);


//Worker 2
var worker2 = new Worker(getScriptPath(function(){
    self.addEventListener('message', function(e) {
        var value = 0;
        while(value <= e.data){
            self.postMessage(value);
            value++;
        }
    }, false);
}));
worker2.addEventListener('message', function(e) {
  document.getElementById("result2").innerHTML = e.data;
}, false);


//Worker 3
var worker3 = new Worker(getScriptPath(function(){
    self.addEventListener('message', function(e) {
        var value = 0;
        while(value <= e.data){
            self.postMessage(value);
            value++;
        }
    }, false);
}));
worker3.addEventListener('message', function(e) {
    document.getElementById("result3").innerHTML = e.data;
}, false);


// Start and send data to our worker.
worker1.postMessage(MAX_VALUE); 
worker2.postMessage(MAX_VALUE); 
worker3.postMessage(MAX_VALUE);
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>

Мы видим, что три потока выполняются параллельно и печатают свое текущее значение на странице.Они не замораживают страницу, поскольку выполняются в фоновом режиме с отдельными потоками.


Многопоточность:с несколькими iframe

Другой способ добиться этого — использовать несколько iframe, каждый из них выполнит поток.Мы можем дать iframe некоторые параметры по URL и iframe может связаться со своим родителем, чтобы получить результат и распечатать его ( iframe должны находиться в том же домене).

Этот пример работает не во всех браузерах! iframe обычно запускается в том же потоке/процессе, что и главная страница (но Firefox и Chromium, похоже, обрабатывают это по-разному).

Поскольку фрагмент кода не поддерживает несколько файлов HTML, я просто приведу здесь разные коды:

индекс.html:

//The 3 iframes containing the code (take the thread id in param)
<iframe id="threadFrame1" src="thread.html?id=1"></iframe>
<iframe id="threadFrame2" src="thread.html?id=2"></iframe>
<iframe id="threadFrame3" src="thread.html?id=3"></iframe>

//Divs that shows the result
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>


<script>
    //This function is called by each iframe
    function threadResult(threadId, result) {
        document.getElementById("result" + threadId).innerHTML = result;
    }
</script>

поток.html:

//Get the parameters in the URL: http://stackoverflow.com/a/1099670/2576706
function getQueryParams(paramName) {
    var qs = document.location.search.split('+').join(' ');
    var params = {}, tokens, re = /[?&]?([^=]+)=([^&]*)/g;
    while (tokens = re.exec(qs)) {
        params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]);
    }
    return params[paramName];
}

//The thread code (get the id from the URL, we can pass other parameters as needed)
var MAX_VALUE = 100000;
(function thread() {
    var threadId = getQueryParams('id');
    for(var i=0; i<MAX_VALUE; i++){
        parent.threadResult(threadId, i);
    }
})();

Имитировать многопоточность

Однопоточный:эмулировать параллелизм JavaScript с помощью setTimeout()

«Наивным» способом было бы выполнить функцию setTimeout() друг за другом вот так:

setTimeout(function(){ /* Some tasks */ }, 0);
setTimeout(function(){ /* Some tasks */ }, 0);
[...]

Но этот метод не работает потому что каждая задача будет выполняться одна за другой.

Мы можем смоделировать асинхронное выполнение, рекурсивно вызывая функцию следующим образом:

var MAX_VALUE = 10000;

function thread1(value, maxValue){
    var me = this;
    document.getElementById("result1").innerHTML = value;
    value++;
  
    //Continue execution
    if(value<=maxValue)
        setTimeout(function () { me.thread1(value, maxValue); }, 0);
}

function thread2(value, maxValue){
    var me = this;
    document.getElementById("result2").innerHTML = value;
    value++;
	
    if(value<=maxValue)
        setTimeout(function () { me.thread2(value, maxValue); }, 0);
}

function thread3(value, maxValue){
    var me = this;
    document.getElementById("result3").innerHTML = value;
    value++;
	
    if(value<=maxValue)
        setTimeout(function () { me.thread3(value, maxValue); }, 0);
}

thread1(0, MAX_VALUE);
thread2(0, MAX_VALUE);
thread3(0, MAX_VALUE);
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>

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


Однопоточный:эмулировать параллелизм JavaScript с помощью доходности

Урожай это новая функция в ECMAScript 6, он работает только на самой старой версии Firefox и Chrome (в Chrome необходимо включить Экспериментальный JavaScript появляясь в chrome://flags/#enable-javascript-harmony).

Ключевое слово доходности приводит к приостановке выполнения функции генератора, и значение выражения, следующего за ключевым словом доходности, возвращается вызывающей стороне генератора.Его можно рассматривать как версию ключевого слова return на основе генератора.

Генератор позволяет приостановить выполнение функции и возобновить его позже.Генератор можно использовать для планирования ваших функций с помощью метода, называемого прыжки на батуте.

Вот пример:

var MAX_VALUE = 10000;

Scheduler = {
	_tasks: [],
	add: function(func){
		this._tasks.push(func);
	},	
	start: function(){
		var tasks = this._tasks;
		var length = tasks.length;
		while(length>0){
			for(var i=0; i<length; i++){
				var res = tasks[i].next();
				if(res.done){
					tasks.splice(i, 1);
					length--;
					i--;
				}
			}
		}
	}	
}


function* updateUI(threadID, maxValue) {
  var value = 0;
  while(value<=maxValue){
	yield document.getElementById("result" + threadID).innerHTML = value;
	value++;
  }
}

Scheduler.add(updateUI(1, MAX_VALUE));
Scheduler.add(updateUI(2, MAX_VALUE));
Scheduler.add(updateUI(3, MAX_VALUE));

Scheduler.start()
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>

С «дополнительными спецификациями» HTML5 больше не нужно взламывать javascript с помощью setTimeout(), setInterval() и т. д.

HTML5 & Friends представляет JavaScript Веб-работники Спецификация.Это API для асинхронного и независимого запуска скриптов.

Ссылки на Спецификация и руководство.

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

В Javascript нет настоящей многопоточности, но вы можете добиться асинхронного поведения, используя setTimeout() и асинхронные запросы AJAX.

Чего именно вы пытаетесь достичь?

Вот просто способ моделировать многопоточность в Javascript

Теперь я собираюсь создать 3 потока, которые будут рассчитывать сложение чисел, числа можно разделить на 13, а числа можно разделить на 3 до 10000000000.И эти три функции не могут выполняться одновременно с тем, что означает параллелизм.Но я покажу вам трюк, который заставит эти функции выполняться рекурсивно одновременно: jsFiddle

Этот код принадлежит мне.

Часть тела

    <div class="div1">
    <input type="button" value="start/stop" onclick="_thread1.control ? _thread1.stop() : _thread1.start();" /><span>Counting summation of numbers till 10000000000</span> = <span id="1">0</span>
</div>
<div class="div2">
    <input type="button" value="start/stop" onclick="_thread2.control ? _thread2.stop() : _thread2.start();" /><span>Counting numbers can be divided with 13 till 10000000000</span> = <span id="2">0</span>
</div>
<div class="div3">
    <input type="button" value="start/stop" onclick="_thread3.control ? _thread3.stop() : _thread3.start();" /><span>Counting numbers can be divided with 3 till 10000000000</span> = <span id="3">0</span>
</div>

Javascript-часть

var _thread1 = {//This is my thread as object
    control: false,//this is my control that will be used for start stop
    value: 0, //stores my result
    current: 0, //stores current number
    func: function () {   //this is my func that will run
        if (this.control) {      // checking for control to run
            if (this.current < 10000000000) {
                this.value += this.current;   
                document.getElementById("1").innerHTML = this.value;
                this.current++;
            }
        }
        setTimeout(function () {  // And here is the trick! setTimeout is a king that will help us simulate threading in javascript
            _thread1.func();    //You cannot use this.func() just try to call with your object name
        }, 0);
    },
    start: function () {
        this.control = true;   //start function
    },
    stop: function () {
        this.control = false;    //stop function
    },
    init: function () {
        setTimeout(function () {
            _thread1.func();    // the first call of our thread
        }, 0)
    }
};
var _thread2 = {
    control: false,
    value: 0,
    current: 0,
    func: function () {
        if (this.control) {
            if (this.current % 13 == 0) {
                this.value++;
            }
            this.current++;
            document.getElementById("2").innerHTML = this.value;
        }
        setTimeout(function () {
            _thread2.func();
        }, 0);
    },
    start: function () {
        this.control = true;
    },
    stop: function () {
        this.control = false;
    },
    init: function () {
        setTimeout(function () {
            _thread2.func();
        }, 0)
    }
};
var _thread3 = {
    control: false,
    value: 0,
    current: 0,
    func: function () {
        if (this.control) {
            if (this.current % 3 == 0) {
                this.value++;
            }
            this.current++;
            document.getElementById("3").innerHTML = this.value;
        }
        setTimeout(function () {
            _thread3.func();
        }, 0);
    },
    start: function () {
        this.control = true;
    },
    stop: function () {
        this.control = false;
    },
    init: function () {
        setTimeout(function () {
            _thread3.func();
        }, 0)
    }
};

_thread1.init();
_thread2.init();
_thread3.init();

Я надеюсь, что этот способ будет полезен.

Вы могли бы использовать Повествовательный JavaScript, компилятор, который преобразует ваш код в конечный автомат, эффективно позволяя эмулировать многопоточность.Это достигается путем добавления в язык «уступающего» оператора (обозначаемого как «->»), который позволяет писать асинхронный код в одном линейном блоке кода.

Новый двигатель v8, который должно выйти сегодня поддерживает это (я думаю)

Другой возможный метод — использование интерпретатора JavaScript в среде JavaScript.

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

Этот подход чем-то похож на веб-работников, но вы предоставляете интерпретатору доступ к глобальной среде браузера.

Я сделал небольшой проект, продемонстрировать это.

Более подробное объяснение в этот пост в блоге.

В необработанном Javascript лучшее, что вы можете сделать, — это использовать несколько асинхронных вызовов (xmlhttprequest), но на самом деле это не многопоточность и очень ограничено. Гугл Гирс добавляет в браузер ряд API, некоторые из которых можно использовать для поддержки потоков.

Если вы не можете или не хотите использовать какие-либо элементы AJAX, используйте iframe или десять!;) Вы можете запускать процессы в iframe параллельно с главной страницей, не беспокоясь о проблемах совместимости между браузерами или проблемах синтаксиса с точечной сетью AJAX и т. д., и вы можете вызывать JavaScript главной страницы (включая импортированный ею JavaScript) из iframe.

Например, в родительском iframe для вызова egFunction() в родительском документе после загрузки содержимого iframe (это асинхронная часть)

parent.egFunction();

Также динамически генерируйте iframe, чтобы основной HTML-код был свободен от них, если хотите.

В Javascript нет потоков, но у нас есть рабочие процессы.

Workers могут быть хорошим выбором, если вам не нужны общие объекты.

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

Я разработал библиотеку под названием задача.js это делает это очень легко сделать.

задача.js Упрощенный интерфейс для запуска кода, интенсивно использующего ЦП, на всех ядрах (node.js и в Интернете).

Примером может быть

function blocking (exampleArgument) {
    // block thread
}

// turn blocking pure function into a worker task
const blockingAsync = task.wrap(blocking);

// run task on a autoscaling worker pool
blockingAsync('exampleArgumentValue').then(result => {
    // do something with result
});

С HTML5 Спецификация вам не нужно писать слишком много JS или искать какие-то хаки.

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

Он поддерживается практически во всех браузерах:

Хром - 4.0+

ИЕ - 10.0+

Мозилла - 3.5+

Сафари - 4.0+

Опера - 11,5+

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top