JavaScript ve Konular


Yanıtlar:


109

En güncel destek bilgileri için http://caniuse.com/#search=worker adresine bakın .

Aşağıdakiler 2009 yılındaki destek durumuydu.


Google için istediğiniz kelimeler JavaScript Çalışan Konularıdır

Gears'ın dışında şu anda mevcut hiçbir şey yok, ancak bunu nasıl uygulayacağınız hakkında bolca konuşma var, bu yüzden sanırım cevap gelecekte değişecek çünkü bu soruyu izleyin.

Gears için ilgili belgeler: WorkerPool API

WHATWG'nin çalışan iş parçacıkları için bir Taslak Tavsiyesi vardır: Web Çalışanları

Ayrıca Mozilla'nın DOM İşçi Konuları da var


Güncelleme: Haziran 2009, JavaScript dizileri için tarayıcı desteğinin geçerli durumu

Firefox 3.5 web çalışanlarına sahiptir. Onları hareket halinde görmek istiyorsanız, web çalışanlarından bazı demolar:

Gears eklentisi Firefox'a da yüklenebilir.

Safari 4 ve WebKit gecelerinde çalışan iş parçacıkları vardır:

Chrome'da Gears'ın pişirilmiş olması nedeniyle, kullanıcıdan onaylama istemi gerektirmesine rağmen iş parçacıkları yapabilir (ve Gears eklentisi yüklü herhangi bir tarayıcıda çalışmasına rağmen web çalışanları için farklı bir API kullanır):

  • Google Gears WorkerPool Demosu (IE, etkileşimi engellediğini görmek için yeterince yavaş çalışmasına rağmen, Chrome ve Firefox'ta test etmek için çok hızlı çalıştığı için iyi bir örnek değil)

IE8 ve IE9 yalnızca Gears eklentisi yüklenmiş konuları yapabilir


1
Safari 4 web çalışanlarını desteklese de, yalnızca Firefox postMessage aracılığıyla karmaşık nesnelerin aktarılmasını destekliyor gibi görünüyor: hapin.mozilla.org/2009/07/working-smarter-not-harder Bespin projesinde gerçek dünya kullanımı hakkındaki bu yazının son paragrafına bakın bağlantılar için Google Gears açısından bu aletlerin işçi API için bir şim ve hangi işçi Safari 4 uygulanmasına eksik özellikler ekleyen ve postMessage arayüzünün üstünde şeffaf özel etkinlikleri hayata ilişkin bilgileri.
Sam Hasler

6
Şimdi IE9 çıktı, "IE8 sadece Gears eklentisi yüklü konuları yapabilirsiniz" için güncelleme yapabilirsiniz "IE8 ve IE9 sadece Gears eklentisi yüklü konuları yapabilirsiniz"
BenoitParis 29:10

2
@ inf3rno, tarayıcı kullanıcı arayüzünü yavaşlatmayan başka bir iş parçacığında uzun hesaplamalar yaptığı için.
Sam Hasler

6
@SamHasler Yanıtınızı gözden geçirmek isteyebilirsiniz. Web çalışanları artık tüm modern masaüstü tarayıcıları tarafından desteklenmektedir. Ayrıca bkz. Caniuse.com/#search=worker
Rob W

2
@SamHasler, Google Gears'ın artık desteklenmediğini de belirtmek gerekir.
skeggse

73

JavaScript'te çoklu iş parçacığı ve Eşzamansız yapmanın farklı yolu

HTML5'ten önce JavaScript, sayfa başına yalnızca bir iş parçacığının yürütülmesine izin verdi.

Asenkron yürütme taklit etmek için bir hacky şekilde oldu Verim , setTimeout(), setInterval(), XMLHttpRequestveya olay işleyicileri ile (bir örnek için bu yazının sonuna bakınız verim vesetTimeout() ).

Ancak HTML5 ile artık çalışanların iş parçacıklarını işlevlerin yürütülmesini paralelleştirmek için kullanabiliriz. İşte bir kullanım örneği.


Gerçek çoklu iş parçacığı

Çoklu iş parçacığı oluşturma: JavaScript Çalışan Konuları

HTML5 Web Çalışan Konularını tanıttı (bkz: tarayıcı uyumlulukları )
Not: IE9 ve önceki sürümleri bunu desteklemez.

Bu çalışan iş parçacıkları, sayfanın performansını etkilemeden arka planda çalışan JavaScript iş parçacıklarıdır. Web Çalışanı hakkında daha fazla bilgi için belgeleri veya bu eğitimi okuyun .

MAX_VALUE değerine sayılan ve sayfamızdaki geçerli hesaplanan değeri gösteren 3 Web Çalışanı iş parçacığına ilişkin basit bir örnek:

//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>

Üç iş parçacığının eşzamanlı olarak yürütüldüğünü görebilir ve geçerli değerlerini sayfada yazdırabiliriz. Ayrılmış iş parçacıkları ile arka planda yürütüldükleri için sayfayı dondurmazlar.


Çoklu iş parçacığı: birden çok iframe ile

Bunu başarmanın başka bir yolu, birden fazla iframe kullanmaktır , her biri bir iş parçacığı yürütür. İframe'e URL ile bazı parametreler verebiliriz ve iframe sonucu almak ve geri yazdırmak için üst öğesiyle iletişim kurabilir ( iframe aynı etki alanında olmalıdır).

Bu örnek tüm tarayıcılarda çalışmaz! iframe'ler genellikle ana sayfa ile aynı iş parçacığında / işlemde çalışır (ancak Firefox ve Chromium farklı şekilde işliyor gibi görünüyor).

Kod pasajı birden fazla HTML dosyasını desteklemediğinden, burada sadece farklı kodlar sunacağım:

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);
    }
})();

Çoklu iş parçacığını taklit et

Tek iş parçacığı: setTimeout () ile JavaScript eşzamanlılığını taklit edin

'Saf' yol, işlevi setTimeout()birbiri ardına şu şekilde yürütmek olacaktır :

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

Ancak bu yöntem çalışmaz, çünkü her görev birbiri ardına yürütülecektir.

İşlevi şu şekilde bu şekilde çağırarak eşzamansız yürütmeyi simüle edebiliriz:

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>

Gördüğünüz gibi, bu ikinci yöntem çok yavaş ve işlevleri yürütmek için ana iş parçacığı kullandığından tarayıcıyı donduruyor.


Tek iş parçacığı: JavaScript eşzamanlılığını getiri ile taklit etme

Verim , ECMAScript 6'daki yeni bir özelliktir, yalnızca Firefox ve Chrome'un en eski sürümünde çalışır (Chrome'da chrome: // flags / # enable-javascript-harmony'de görünen Deneysel JavaScript'i etkinleştirmeniz gerekir).

Verim anahtar sözcüğü, jeneratör işlevi yürütmesinin duraklamasına neden olur ve verim anahtar sözcüğünü izleyen ifadenin değeri, üretecin arayanına döndürülür. Dönüş anahtar kelimesinin jeneratör tabanlı bir sürümü olarak düşünülebilir.

Bir jeneratör, bir fonksiyonun yürütülmesini askıya almanıza ve daha sonra devam etmenize izin verir. Bir jeneratör, trambolin adı verilen bir teknikle işlevlerinizi programlamak için kullanılabilir .

İşte örnek:

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>


3
Bu gerçekten en iyi cevap olmalı.
Jerry Liu

14

HTML5 "side-specs" ile artık javascript'i setTimeout (), setInterval () vb.

HTML5 & Friends, javascript Web Workers spesifikasyonunu sunar. Komut dosyalarını eşzamansız ve bağımsız olarak çalıştırmak için bir API'dir.

Bağlantılar şartname ve öğretici .


11

JavaScript'te gerçek bir iş parçacığı yoktur. JavaScript, biçimlendirilebilir dil olduğu için, bazılarını taklit etmenize izin verir. Geçen gün karşılaştığım bir örnek .


1
"Gerçek iplik geçirme" ile ne demek istiyorsun? Yeşil iş parçacıkları gerçek iş parçacıklarıdır.
Wes

10

Javascript'te gerçek bir çoklu iş parçacığı yoktur, ancak kullanarak asenkron davranış elde edebilirsiniz. setTimeout() eşzamansız AJAX isteklerini .

Tam olarak neyi başarmak istiyorsun?


7

Javascript'te çoklu iş parçacığını simüle etmenin bir yolu

Şimdi sayılar eklenmesini hesaplayacak 3 iş parçacığı oluşturacağım, sayılar 13'e bölünebilir ve sayılar 3'e 10000000000'e kadar bölünebilir. Ama size bu işlevlerin aynı zamanda yinelemeli çalışmasını sağlayacak bir numara göstereceğim: jsFiddle

Bu kod bana ait.

Vücut parçası

    <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 Bölümü

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();

Umarım bu şekilde yardımcı olur.


6

Kodunuzu bir durum makinesine dönüştürecek ve etkili bir şekilde iş parçacığını taklit etmenizi sağlayacak bir derleyici olan Anlatım JavaScript'i kullanabilirsiniz . Bunu, tek bir doğrusal kod bloğunda eşzamansız kod yazmanıza izin veren dile "verim" operatörü ('->' olarak işaretlenmiş) ekleyerek yapar.



3

Ham Javascript'te yapabileceğiniz en iyi şey, birkaç eşzamansız çağrıyı (xmlhttprequest) kullanmaktır, ancak bu gerçekten iş parçacığı ve çok sınırlı değildir. Google Gears , tarayıcıya bazıları iplik geçirme desteği için kullanılabilecek bir dizi API ekler.


1
Google Gears API'sı artık kullanılamıyor.
Ludovic Feltz

3

Herhangi bir AJAX öğesi kullanamazsanız veya istemiyorsanız, bir iframe veya on kullanın! ;) Çapraz tarayıcı ile karşılaştırılabilir sorunlar veya dot net AJAX vb. İle sözdizimi sorunları hakkında endişelenmeden iframe'lerde ana sayfaya paralel olarak çalışan işlemleriniz olabilir ve ana sayfanın JavaScript'ini (içe aktardığı JavaScript dahil) iframe.

Örneğin, bir üst iframe'de, egFunction()iframe içeriği yüklendikten sonra üst belgeyi aramak için (bu eşzamansız bölümdür)

parent.egFunction();

Dinamik olarak iframe'leri de oluşturun, böylece isterseniz ana html kodu bunlardan arınmış olur.


1
Bu açıklama benim sevme biraz fazla kısa oldu. Bu tekniğin nasıl yapılacağı hakkında ayrıntılı bilgi verebilir veya bazı kodları gösteren bir eğiticiye bağlantı gönderebilir misiniz?
oligofren

3

Başka bir olası yöntem, javascript ortamında bir javascript yorumlayıcısı kullanmaktır.

Birden çok yorumlayıcı oluşturarak ve bunların ana iş parçacığından yürütülmesini denetleyerek, her iş parçacığının kendi ortamında çalıştığı çoklu iş parçacığını simüle edebilirsiniz.

Yaklaşım web çalışanlarına biraz benzer, ancak tercümanın tarayıcı küresel ortamına erişmesini sağlarsınız.

Bunu göstermek için küçük bir proje yaptım .

Bu blog yazısında daha ayrıntılı bir açıklama .


1

Javascript'te konu yok, ancak işçiler var.

Paylaşılan nesnelere ihtiyacınız yoksa işçiler iyi bir seçim olabilir.

Tarayıcı uygulamalarının çoğu, aslında tüm çekirdekleri kullanmanıza olanak tanıyarak çalışanları tüm çekirdeklere yayar. Bunun bir demosunu burada görebilirsiniz .

Bunu çok kolaylaştıran task.js adında bir kütüphane geliştirdim .

task.js Tüm çekirdeklerde (node.js ve web) CPU yoğun kod çalıştırmak için basitleştirilmiş arayüz

Bir örnek

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
});

0

HTML5 spesifikasyonu ile aynı için çok fazla JS yazmanız veya bazı hack'ler bulmanız gerekmez.

HTML5'te sunulan özelliklerden biri de Web Çalışanları diğer komut dosyalarından bağımsız olarak, sayfanın performansını etkilemeden arka planda çalışan JavaScript olan .

Hemen hemen tüm tarayıcılarda desteklenir:

Chrome - 4.0+

IE - 10.0+

Mozilla - 3.5+

Safari - 4.0+

Opera - 11.5+

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.