Apakah ada cara untuk melakukan multi-threading di JavaScript?
javascript
multithreading
Niyaz
sumber
sumber
Jawaban:
Lihat http://caniuse.com/#search=worker untuk info dukungan terbaru.
Berikut ini adalah keadaan dukungan sekitar tahun 2009.
Kata-kata yang ingin Anda cari di Google adalah JavaScript Worker Threads
Selain dari Gears tidak ada yang tersedia saat ini, tetapi ada banyak pembicaraan tentang bagaimana menerapkan ini jadi saya kira perhatikan pertanyaan ini karena jawabannya pasti akan berubah di masa depan.
Berikut dokumentasi yang relevan untuk Gears: WorkerPool API
WHATWG memiliki Rekomendasi Draf untuk utas pekerja: Pekerja Web
Dan ada juga DOM Worker Threads dari Mozilla
Pembaruan: Juni 2009, status dukungan browser saat ini untuk utas JavaScript
Firefox 3.5 memiliki pekerja web. Beberapa demo pekerja web, jika Anda ingin melihat mereka beraksi:
Plugin Gears juga dapat diinstal di Firefox.
Safari 4 , dan nightlies WebKit memiliki utas pekerja:
Chrome telah memasukkan Gears, sehingga ia dapat melakukan utas, meskipun itu membutuhkan prompt konfirmasi dari pengguna (dan ini menggunakan API yang berbeda untuk pekerja web, meskipun itu akan bekerja di browser apa pun dengan plugin Gears terpasang):
IE8 dan IE9 hanya dapat melakukan utas dengan plugin Gears terpasang
sumber
Cara berbeda untuk melakukan multi-threading dan Asynchronous di JavaScript
Sebelum HTML5 JavaScript hanya mengizinkan eksekusi satu utas per halaman.
Ada beberapa cara Hacky untuk mensimulasikan eksekusi asynchronous dengan Yield ,
setTimeout()
,setInterval()
,XMLHttpRequest
atau event handler (lihat akhir posting ini untuk contoh dengan hasil dansetTimeout()
).Tetapi dengan HTML5 sekarang kita dapat menggunakan Worker Threads untuk memparalelkan pelaksanaan fungsi. Berikut ini contoh penggunaannya.
Multi-threading nyata
Multi-threading: JavaScript Worker Threads
HTML5 memperkenalkan Web Worker Threads (lihat: kompatibilitas browser )
Catatan: IE9 dan versi sebelumnya tidak mendukungnya.
Utas pekerja ini adalah utas JavaScript yang berjalan di latar belakang tanpa memengaruhi kinerja laman. Untuk informasi lebih lanjut tentang Web Worker baca dokumentasi atau tutorial ini .
Berikut adalah contoh sederhana dengan 3 utas Web Worker yang dihitung hingga MAX_VALUE dan menunjukkan nilai yang dihitung saat ini di halaman kami:
//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>
We can see that the three threads are executed in concurrency and print their current value in the page. They don't freeze the page because they are executed in the background with separated threads.
Multi-threading: with multiple iframes
Another way to achieve this is to use multiple iframes, each one will execute a thread. We can give the iframe some parameters by the URL and the iframe can communicate with his parent in order to get the result and print it back (the iframe must be in the same domain).
This example doesn't work in all browsers! iframes usually run in the same thread/process as the main page (but Firefox and Chromium seem to handle it differently).
Since the code snippet does not support multiple HTML files, I will just provide the different codes here:
index.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>
thread.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); } })();
Simulate multi-threading
Single-thread: emulate JavaScript concurrency with setTimeout()
The 'naive' way would be to execute the function
setTimeout()
one after the other like this:setTimeout(function(){ /* Some tasks */ }, 0); setTimeout(function(){ /* Some tasks */ }, 0); [...]
But this method does not work because each task will be executed one after the other.
We can simulate asynchronous execution by calling the function recursively like this:
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>
As you can see this second method is very slow and freezes the browser because it uses the main thread to execute the functions.
Single-thread: emulate JavaScript concurrency with yield
Yield is a new feature in ECMAScript 6, it only works on the oldest version of Firefox and Chrome (in Chrome you need to enable Experimental JavaScript appearing in chrome://flags/#enable-javascript-harmony).
A generator allows you to suspend execution of a function and resume it later. A generator can be used to schedule your functions with a technique called trampolining.
Here is the example:
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>
sumber
With the HTML5 "side-specs" no need to hack javascript anymore with setTimeout(), setInterval(), etc.
HTML5 & Friends introduces the javascript Web Workers specification. It is an API for running scripts asynchronously and independently.
Links to the specification and a tutorial.
sumber
There's no true threading in JavaScript. JavaScript being the malleable language that it is, does allow you to emulate some of it. Here is an example I came across the other day.
sumber
There is no true multi-threading in Javascript, but you can get asynchronous behavior using
setTimeout()
and asynchronous AJAX requests.What exactly are you trying to accomplish?
sumber
Here is just a way to simulate multi-threading in Javascript
Now I am going to create 3 threads which will calculate numbers addition, numbers can be divided with 13 and numbers can be divided with 3 till 10000000000. And these 3 functions are not able to run in same time as what Concurrency means. But I will show you a trick that will make these functions run recursively in the same time : jsFiddle
This code belongs to me.
Body Part
<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 Part
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();
I hope this way will be helpful.
sumber
You could use Narrative JavaScript, a compiler that will transforms your code into a state machine, effectively allowing you to emulate threading. It does so by adding a "yielding" operator (notated as '->') to the language that allows you to write asynchronous code in a single, linear code block.
sumber
The new v8 engine which should come out today supports it (i think)
sumber
In raw Javascript, the best that you can do is using the few asynchronous calls (xmlhttprequest), but that's not really threading and very limited. Google Gears adds a number of APIs to the browser, some of which can be used for threading support.
sumber
If you can't or don't want to use any AJAX stuff, use an iframe or ten! ;) You can have processes running in iframes in parallel with the master page without worrying about cross browser comparable issues or syntax issues with dot net AJAX etc, and you can call the master page's JavaScript (including the JavaScript that it has imported) from an iframe.
E.g, in a parent iframe, to call
egFunction()
in the parent document once the iframe content has loaded (that's the asynchronous part)Dynamically generate the iframes too so the main html code is free from them if you want.
sumber
Another possible method is using an javascript interpreter in the javascript environment.
By creating multiple interpreters and controlling their execution from the main thread, you can simulate multi-threading with each thread running in its own environment.
The approach is somewhat similar to web workers, but you give the interpreter access to the browser global environment.
I made a small project to demonstrate this.
A more detailed explanation in this blog post.
sumber
Javascript doesn't have threads, but we do have workers.
Workers may be a good choice if you don't need shared objects.
Most browser implementations will actually spread workers across all cores allowing you to utilize all cores. You can see a demo of this here.
I have developed a library called task.js that makes this very easy to do.
A example would be
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 });
sumber
With HTML5 specification you do not need to write too much JS for the same or find some hacks.
One of the feature introduced in HTML5 is Web Workers which is JavaScript running in the background,independently of other scripts, without affecting the performance of the page.
It is supported in almost all browsers :
Chrome - 4.0+
IE - 10.0+
Mozilla - 3.5+
Safari - 4.0+
Opera - 11.5+
sumber