JavaScript tek iş parçacıklıdır, yani aynı anda yalnızca bir işlem gerçekleştirebilir. Bu sezgiseldir ve web’deki birçok durum için iyi çalışır, ancak veri işleme, ayrıştırma, hesaplama veya analiz gibi ağır kaldırma görevleri yapmamız gerektiğinde sorunlu hale gelebilir. Web’de giderek daha karmaşık uygulamalar sunuldukça, çok iş parçacıklı işlemeye olan ihtiyaç artıyor.
Web platformunda, iş parçacığı ve paralellik için ana ilke, Web Çalışanları API’sı. İşçiler, üzerinde hafif bir soyutlamadır. işletim sistemi konuları bu, iş parçacığı arası iletişim için API’yi geçen bir iletiyi ortaya çıkarır. Bu, maliyetli hesaplamalar gerçekleştirirken veya büyük veri kümeleri üzerinde çalışırken son derece yararlı olabilir ve bir veya daha fazla arka plan iş parçacığında pahalı işlemleri gerçekleştirirken ana iş parçacığının sorunsuz çalışmasına izin verir.
Aşağıda, bir çalışan komut dosyasının ana iş parçacığından gelen mesajları dinlediği ve kendi mesajlarını geri göndererek yanıt verdiği tipik bir çalışan kullanımı örneği verilmiştir:
sayfa.js:
const worker = new Worker('worker.js');
worker.addEventListener('message', e => {
console.log(e.data);
});
worker.postMessage('hello');
işçi.js:
addEventListener('message', e => {
if (e.data === 'hello') {
postMessage('world');
}
});
Web Worker API, on yılı aşkın bir süredir çoğu tarayıcıda mevcuttur. Bu, çalışanların mükemmel tarayıcı desteğine sahip olduğu ve iyi bir şekilde optimize edildiği anlamına gelirken, aynı zamanda JavaScript modüllerinden çok önce geldikleri anlamına da gelir. Çalışanlar tasarlanırken bir modül sistemi olmadığı için, bir işçiye kod yüklemek ve komut dosyaları oluşturmak için kullanılan API, 2009’da yaygın olarak kullanılan eşzamanlı komut dosyası yükleme yaklaşımlarına benzer kaldı.
Tarih: klasik işçiler #
Worker yapıcısı bir klasik senaryo Belge URL’sine göreli olan URL. Hemen yeni çalışan örneğine bir başvuru döndürür, bu da bir mesajlaşma arabiriminin yanı sıra terminate()
işçiyi anında durduran ve yok eden yöntem.
const worker = new Worker('worker.js');
Bir importScripts()
işlevi, web çalışanları içinde ek kod yüklemek için kullanılabilir, ancak her komut dosyasını almak ve değerlendirmek için çalışanın yürütülmesini duraklatır. Ayrıca komut dosyalarını bir klasik gibi küresel kapsamda yürütür. <script>
etiketi, yani bir betikteki değişkenlerin üzerine başka bir betikteki değişkenler yazılabilir.
işçi.js:
importScripts('greet.js');
// ^ could block for seconds
addEventListener('message', e => {
postMessage(sayHello());
});
selam.js:
// global to the whole worker
function sayHello() {
return 'world';
}
Bu nedenle, web çalışanları tarihsel olarak bir uygulamanın mimarisi üzerinde çok büyük bir etki yaratmıştır. Geliştiriciler, modern geliştirme uygulamalarından vazgeçmeden web çalışanlarını kullanmayı mümkün kılmak için akıllı araçlar ve geçici çözümler oluşturmak zorunda kaldılar. Örnek olarak, webpack gibi paketleyiciler, küçük bir modül yükleyici uygulamasını, kullanılan koda yerleştirir. importScripts()
kod yükleme için, ancak değişken çarpışmalarını önlemek ve bağımlılık içe ve dışa aktarmalarını simüle etmek için modülleri işlevlere sarar.
Modül çalışanlarını girin #
Web çalışanları için ergonomi ve performans avantajlarına sahip yeni bir mod JavaScript modülleri modül çalışanları adı verilen Chrome 80’de gönderilir. bu Worker
yapıcı şimdi yenisini kabul ediyor {type:"module"}
komut dosyasının yüklenmesini ve yürütülmesini eşleşecek şekilde değiştiren seçenek <script type="module">
.
const worker = new Worker('worker.js', {
type: 'module'
});
Modül çalışanları standart JavaScript modülleri olduğundan, import ve export deyimlerini kullanabilirler. Tüm JavaScript modüllerinde olduğu gibi, bağımlılıklar belirli bir bağlamda (ana iş parçacığı, çalışan vb.) yalnızca bir kez yürütülür ve gelecekteki tüm içe aktarmalar, halihazırda yürütülmekte olan modül örneğine başvurur. JavaScript modüllerinin yüklenmesi ve yürütülmesi de tarayıcılar tarafından optimize edilmiştir. Bir modülün bağımlılıkları, modül yürütülmeden önce yüklenebilir, bu da tüm modül ağaçlarının paralel olarak yüklenmesine olanak tanır. Modül yükleme, ayrıştırılmış kodu da önbelleğe alır; bu, ana iş parçacığında ve bir çalışanda kullanılan modüllerin yalnızca bir kez ayrıştırılması gerektiği anlamına gelir.
JavaScript modüllerine geçmek, aynı zamanda dinamik içe aktarma çalışanın yürütülmesini engellemeden kodun geç yüklenmesi için. Dinamik içe aktarma, kullanmaktan çok daha açıktır importScripts()
Bağımlılıkları yüklemek için, içe aktarılan modülün dışa aktarmaları global değişkenlere dayanmak yerine döndürülür.
işçi.js:
import { sayHello } from './greet.js';
addEventListener('message', e => {
postMessage(sayHello());
});
selam.js:
import greetings from './data.js';
export function sayHello() {
return greetings.hello;
}
Mükemmel performans sağlamak için eski importScripts()
yöntem, modül çalışanları içinde mevcut değildir. Çalışanları JavaScript modüllerini kullanacak şekilde değiştirmek, tüm kodun yüklendiği anlamına gelir. katı mod. Diğer bir önemli değişiklik ise, değerinin this
bir JavaScript modülünün üst düzey kapsamındaki undefined
, oysa klasik çalışanlarda değer, çalışanın küresel kapsamıdır. Neyse ki, her zaman bir self
global kapsama bir referans sağlayan global. DOM’un yanı sıra hizmet çalışanları da dahil olmak üzere tüm çalışan türlerinde kullanılabilir.
Çalışanları önceden yükle modulepreload
#
Modül çalışanlarıyla birlikte gelen önemli bir performans iyileştirmesi, çalışanları ve bağımlılıklarını önceden yükleme yeteneğidir. Modül çalışanları ile betikler standart JavaScript modülleri olarak yüklenir ve yürütülür; bu, kullanılarak önceden yüklenebilecekleri ve hatta önceden ayrıştırılabilecekleri anlamına gelir. modulepreload
:
<!-- preloads worker.js and its dependencies: -->
link rel="modulepreload" href="worker.js">script>
addEventListener('load', () => {
// our worker code is likely already parsed and ready to execute!
const worker = new Worker('worker.js', { type: 'module' });
});
</script>
Önceden yüklenmiş modüller ayrıca hem ana iş parçacığı hem de modül çalışanları tarafından kullanılabilir. Bu, her iki bağlamda içe aktarılan modüller için veya bir modülün ana iş parçacığında mı yoksa bir çalışanda mı kullanılacağını önceden bilmenin mümkün olmadığı durumlarda kullanışlıdır.
Önceden, web çalışan betiklerini önceden yüklemek için mevcut seçenekler sınırlıydı ve mutlaka güvenilir değildi. Klasik çalışanların ön yükleme için kendi “çalışan” kaynak türü vardı, ancak hiçbir tarayıcı uygulanmadı <link rel="preload" as="worker">
. Sonuç olarak, web çalışanlarını önceden yüklemek için mevcut olan birincil teknik şuydu: <link rel="prefetch">
tamamen HTTP önbelleğine dayanan. Doğru önbelleğe alma üst bilgileriyle birlikte kullanıldığında bu, çalışan başlatmanın çalışan komut dosyasını indirmek için beklemek zorunda kalmasını önlemeyi mümkün kıldı. Ancak, aksine modulepreload
bu teknik, ön yükleme bağımlılıklarını veya ön ayrıştırmayı desteklemiyordu.
Peki ya ortak çalışanlar? #
Paylaşılan işçiler Chrome 83’ten itibaren JavaScript modülleri desteğiyle güncellendi. {type:"module"}
seçeneği artık çalışan komut dosyasını klasik bir komut dosyası yerine bir modül olarak yüklüyor:
const worker = new SharedWorker('/worker.js', {
type: 'module'
});
JavaScript modüllerinin desteklenmesinden önce, SharedWorker()
yapıcı yalnızca bir URL ve isteğe bağlı bir URL bekliyordu. name
argüman. Bu, klasik paylaşılan çalışan kullanımı için çalışmaya devam edecek; ancak modül paylaşımlı çalışanlarını oluşturmak için yeni options
argüman. bu mevcut seçenekler dahil olmak üzere özel bir çalışan için olanlarla aynıdır. name
öncekinin yerini alan seçenek name
argüman.
Peki ya servis elemanı? #
Hizmet çalışanı belirtimi zaten güncellendi giriş noktası olarak bir JavaScript modülünün kabul edilmesini desteklemek için aynı {type:"module"}
seçeneği, ancak bu değişiklik tarayıcılarda henüz uygulanmadı. Bu gerçekleştiğinde, aşağıdaki kodu kullanarak bir JavaScript modülü kullanarak bir hizmet çalışanının örneğini oluşturmak mümkün olacaktır:
navigator.serviceWorker.register('/sw.js', {
type: 'module'
});
Spesifikasyon güncellendiğine göre, tarayıcılar yeni davranışı uygulamaya başlıyor. JavaScript modüllerini hizmet çalışanına getirmekle ilgili bazı ekstra zorluklar olduğundan bu işlem zaman alır. Servis çalışanı kaydı gerekir içe aktarılan komut dosyalarını önceki önbelleğe alınmış sürümleriyle karşılaştırın bir güncellemenin tetiklenip tetiklenmeyeceğini belirlerken ve bunun hizmet çalışanları için kullanıldığında JavaScript modülleri için uygulanması gerekir. Ayrıca, servis çalışanlarının şunları yapabilmesi gerekir: önbelleği atla güncellemeleri kontrol ederken belirli durumlarda komut dosyaları için.