Web Çalışanlarıyla Bir React Uygulamasında Uzun Süren Görevleri Yönetme
Yayınlanan: 2022-03-10Web uygulamaları söz konusu olduğunda yanıt süresi çok önemlidir. Uygulamanız ne yapıyor olursa olsun, kullanıcılar anlık yanıtlar talep eder. Web uygulaması kullanıcıları, yalnızca bir kişinin adını veya çatırdayan numaralarını görüntülüyor olsun, uygulamanızın her seferinde komutlarına yanıt vermesini ister. Bazen JavaScript'in tek iş parçacıklı doğası göz önüne alındığında bunu başarmak zor olabilir. Ancak bu makalede, daha iyi bir deneyim sunmak için Web Worker API'sinden nasıl yararlanabileceğimizi öğreneceğiz.
Bu makaleyi yazarken aşağıdaki varsayımlarda bulundum:
- Devam edebilmek için JavaScript ve belge API'si hakkında en azından biraz bilginiz olmalıdır;
- Ayrıca Create React App kullanarak yeni bir React projesini başarıyla başlatabilmeniz için React hakkında çalışma bilgisine sahip olmalısınız.
Bu konuyla ilgili daha fazla içgörüye ihtiyacınız varsa, hızınızı artırmanıza yardımcı olmak için "İleri Kaynaklar" bölümüne birkaç bağlantı ekledim.
İlk olarak, Web Workers ile başlayalım.
Web Çalışanı Nedir?
Web Çalışanlarını ve çözmeleri gereken sorunu anlamak için JavaScript kodunun çalışma zamanında nasıl yürütüldüğünü kavramak gerekir. Çalışma zamanı sırasında, JavaScript kodu sırayla ve adım adım yürütülür. Bir kod parçası bittiğinde, sıradaki kod çalışmaya başlar ve bu böyle devam eder. Teknik terimlerle, JavaScript'in tek iş parçacıklı olduğunu söylüyoruz. Bu davranış, bir kod parçası çalışmaya başladığında, ardından gelen her kodun bu kodun yürütmeyi bitirmesini beklemesi gerektiği anlamına gelir. Böylece, her kod satırı, kendisinden sonra gelen her şeyin yürütülmesini “engeller”. Bu nedenle, her bir kod parçasının mümkün olduğu kadar çabuk bitmesi arzu edilir. Bir kod parçasının tamamlanması çok uzun sürerse, programımız çalışmayı durdurmuş gibi görünür. Tarayıcıda bu, donmuş, yanıt vermeyen bir sayfa olarak kendini gösterir. Bazı aşırı durumlarda, sekme tamamen donacaktır.
Tek şeritte sürüş hayal edin. Önünüzdeki sürücülerden herhangi biri herhangi bir nedenle hareket etmeyi bırakırsa, trafik sıkışıklığı yaşarsınız. Java gibi bir programla trafik diğer şeritlerde devam edebilir. Bu nedenle Java'nın çok iş parçacıklı olduğu söylenir. Web Çalışanları, çok iş parçacıklı davranışı JavaScript'e getirme girişimidir.
Aşağıdaki ekran görüntüsü, Web Worker API'nin birçok tarayıcı tarafından desteklendiğini göstermektedir, bu nedenle onu kullanırken kendinizi güvende hissetmelisiniz.

Web Çalışanları, kullanıcı arayüzüne müdahale etmeden arka plan iş parçacıklarında çalışır ve olay işleyicileri aracılığıyla kendilerini oluşturan kodla iletişim kurarlar.
Bir Web Çalışanının mükemmel bir tanımı MDN'den gelir:
“İşçi, bir yapıcı kullanılarak oluşturulan bir nesnedir (örneğin, adlandırılmış bir JavaScript dosyasını çalıştıranWorker()
— bu dosya, çalışan iş parçacığında çalışacak kodu içerir; işçiler, geçerliwindow
farklı başka bir küresel bağlamda çalışır. , geçerli genel kapsamı almak içinwindow
kısayolunu kullanarak (birWorker
içindekiself
yerine bir hata döndürür."
Worker
yapıcısı kullanılarak bir işçi oluşturulur.
const worker = new Worker('worker-file.js')
Bazı istisnalar dışında çoğu kodu bir web çalışanı içinde çalıştırmak mümkündür. Örneğin, bir çalışanın içinden DOM'yi değiştiremezsiniz. document
API'sine erişim yok.
İşçiler ve onları oluşturan iş parçacığı, postMessage()
yöntemini kullanarak birbirlerine mesaj gönderir. Benzer şekilde, mesajlara onmessage
olay işleyicisini kullanarak yanıt verirler. Bu farkı yakalamak önemli. Mesaj gönderme bir yöntem kullanılarak gerçekleştirilir; bir iletiyi geri almak için bir olay işleyicisi gerekir. Alınan mesaj, olayın data
özniteliğinde bulunur. Bir sonraki bölümde bunun bir örneğini göreceğiz. Ancak, tartıştığımız işçi tipine “adanmış işçi” dendiğini hemen belirteyim. Bu, çalışana yalnızca onu çağıran komut dosyası tarafından erişilebilir olduğu anlamına gelir. Birden çok komut dosyasından erişilebilen bir çalışana sahip olmak da mümkündür. Bunlara paylaşılan çalışanlar denir ve aşağıda gösterildiği gibi SharedWorker
yapıcısı kullanılarak oluşturulur.
const sWorker = new SharedWorker('shared-worker-file.js')
Çalışanlar hakkında daha fazla bilgi edinmek için lütfen bu MDN makalesine bakın. Bu makalenin amacı, Web çalışanlarını kullanmaya başlamanızı sağlamaktır. n'inci Fibonacci sayısını hesaplayarak konuya gelelim.
N. Fibonacci Sayısını Hesaplama
Not: Bu ve sonraki iki bölüm için, uygulamayı çalıştırmak için VSCode'da Live Server kullanıyorum. Kesinlikle başka bir şey kullanabilirsiniz.
İşte beklediğiniz bölüm. Sonunda Web Çalışanlarını çalışırken görmek için bazı kodlar yazacağız. O kadar hızlı değil. Çözdüğü türden sorunlarla karşılaşmadıkça, bir Web Çalışanının yaptığı işi takdir etmeyiz. Bu bölümde örnek bir problem göreceğiz ve sonraki bölümde bir web çalışanının daha iyi yapmamıza nasıl yardımcı olduğunu göreceğiz.
Kullanıcıların n'inci Fibonacci sayısını hesaplamasına izin veren bir web uygulaması oluşturduğunuzu hayal edin. 'Fibonacci sayısı' terimi konusunda yeniyseniz, bununla ilgili daha fazla bilgiyi burada bulabilirsiniz, ancak özet olarak, Fibonacci sayıları, her sayı kendinden önceki iki sayının toplamı olacak şekilde bir sayı dizisidir.
Matematiksel olarak şu şekilde ifade edilir:

Böylece dizinin ilk birkaç numarası:
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 ...
Bazı kaynaklarda dizi F 0 = 0
ile başlar, bu durumda aşağıdaki formül n > 1
için geçerlidir:

Bu yazıda F 1 = 1'den başlayacağız. Formülden hemen görebileceğimiz bir şey, sayıların yinelemeli bir model izlemesidir. Şimdi elimizdeki görev, n'inci Fibonacci sayısını (FN) hesaplamak için özyinelemeli bir fonksiyon yazmaktır.
Birkaç denemeden sonra aşağıdaki işlevi kolayca bulabileceğinize inanıyorum.
const fib = n => { if (n < 2) { return n // or 1 } else { return fib(n - 1) + fib(n - 2) } }
İşlev basittir. n, 2'den küçükse, n (veya 1) döndürün, aksi takdirde n-1
ve n-2
FN'lerin toplamını döndürün. Ok fonksiyonları ve üçlü operatör ile tek satırlık bir çizgi oluşturabiliriz.
const fib = n => (n < 2 ? n : fib(n-1) + fib(n-2))
Bu işlevin zaman karmaşıklığı 0(2 n )
. Bu basitçe, n'nin değeri arttıkça, toplamı hesaplamak için gereken zamanın katlanarak arttığı anlamına gelir. Bu, büyük n değerleri için kullanıcı arayüzümüze potansiyel olarak müdahale edebilecek gerçekten uzun süren bir görev sağlar. Bunu eylemde görelim.
Not : Bu, bu sorunu çözmenin en iyi yolu değildir. Bu yöntemi kullanma seçimim bu makalenin amacı içindir.
Başlamak için yeni bir klasör oluşturun ve istediğiniz gibi adlandırın. Şimdi bu klasörün içinde bir src/
klasörü oluşturun. Ayrıca, kök klasörde bir index.html
dosyası oluşturun. src/
klasörünün içinde index.js
adında bir dosya oluşturun.
index.html
açın ve aşağıdaki HTML kodunu ekleyin.
<!DOCTYPE html> <html> <head> <link rel="stylesheet" href="styles.css"> </head> <body> <div class="heading-container"> <h1>Computing the nth Fibonnaci number</h1> </div> <div class="body-container"> <p id='error' class="error"></p> <div class="input-div"> <input id='number-input' class="number-input" type='number' placeholder="Enter a number" /> <button id='submit-btn' class="btn-submit">Calculate</button> </div> <div id='results-container' class="results"></div> </div> <script src="/src/index.js"></script> </body> </html>
Bu kısım çok basit. Öncelikle bir başlığımız var. Ardından, girdisi ve düğmesi olan bir kapsayıcımız var. Bir kullanıcı bir sayı girer ve ardından “Hesapla”ya tıklar. Ayrıca hesaplamanın sonucunu tutacak bir kapsayıcımız var. Son olarak, src/index.js
dosyasını bir script
etiketine dahil ediyoruz.
Stil sayfası bağlantısını silebilirsiniz. Ama vaktiniz kısıtlıysa, kullanabileceğiniz bazı CSS tanımladım. Kök klasörde styles.css
dosyasını oluşturmanız ve aşağıdaki stilleri eklemeniz yeterlidir:
body { margin: 0; padding: 0; box-sizing: border-box; } .body-container, .heading-container { padding: 0 20px; } .heading-container { padding: 20px; color: white; background: #7a84dd; } .heading-container > h1 { margin: 0; } .body-container { width: 50% } .input-div { margin-top: 15px; margin-bottom: 15px; display: flex; align-items: center; } .results { width: 50vw; } .results>p { font-size: 24px; } .result-div { padding: 5px 10px; border-radius: 5px; margin: 10px 0; background-color: #e09bb7; } .result-div p { margin: 5px; } span.bold { font-weight: bold; } input { font-size: 25px; } p.error { color: red; } .number-input { padding: 7.5px 10px; } .btn-submit { padding: 10px; border-radius: 5px; border: none; background: #07f; font-size: 24px; color: white; cursor: pointer; margin: 0 10px; }
Şimdi src/index.js
açın, yavaş yavaş geliştirelim. Aşağıdaki kodu ekleyin.
const fib = (n) => (n < 2 ? n : fib(n - 1) + fib(n - 2)); const ordinal_suffix = (num) => { // 1st, 2nd, 3rd, 4th, etc. const j = num % 10; const k = num % 100; switch (true) { case j === 1 && k !== 11: return num + "st"; case j === 2 && k !== 12: return num + "nd"; case j === 3 && k !== 13: return num + "rd"; default: return num + "th"; } }; const textCont = (n, fibNum, time) => { const nth = ordinal_suffix(n); return ` <p id='timer'>Time: <span class='bold'>${time} ms</span></p> <p><span class="bold" id='nth'>${nth}</span> fibonnaci number: <span class="bold" id='sum'>${fibNum}</span></p> `; };
Burada üç fonksiyonumuz var. Birincisi, n'inci FN'yi hesaplamak için daha önce gördüğümüz fonksiyondur. İkinci işlev, bir tamsayıya uygun bir son ek eklemek için yalnızca bir yardımcı işlevdir. Üçüncü işlev, bazı argümanları alır ve daha sonra DOM'a ekleyeceğimiz bir işaretleme çıkarır. İlk argüman, FN'si hesaplanan sayıdır. İkinci argüman hesaplanan FN'dir. Son argüman, hesaplamayı gerçekleştirmek için geçen zamandır.
Hala src/index.js
içinde, aşağıdaki kodu bir öncekinin hemen altına ekleyin.
const errPar = document.getElementById("error"); const btn = document.getElementById("submit-btn"); const input = document.getElementById("number-input"); const resultsContainer = document.getElementById("results-container"); btn.addEventListener("click", (e) => { errPar.textContent = ''; const num = window.Number(input.value); if (num < 2) { errPar.textContent = "Please enter a number greater than 2"; return; } const startTime = new Date().getTime(); const sum = fib(num); const time = new Date().getTime() - startTime; const resultDiv = document.createElement("div"); resultDiv.innerHTML = textCont(num, sum, time); resultDiv.className = "result-div"; resultsContainer.appendChild(resultDiv); });
İlk olarak, HTML dosyamızdaki DOM
düğümlerini almak için document
API'sini kullanırız. Hata mesajlarını göstereceğimiz paragrafa bir referans alıyoruz; girdi; hesapla düğmesi ve sonuçlarımızı göstereceğimiz kapsayıcı.
Ardından, düğmeye bir "tıklama" olay işleyicisi ekliyoruz. Butona tıklandığında input elementinin içinde ne varsa alıp sayıya çeviriyoruz, 2'den az bir şey alırsak hata mesajı veriyor ve geri dönüyoruz. 2'den büyük bir sayı alırsak devam ederiz. İlk olarak, şimdiki zamanı kaydederiz. Bundan sonra, FN'yi hesaplıyoruz. Bu bittiğinde, hesaplamanın ne kadar sürdüğünü gösteren bir zaman farkı elde ederiz. Kodun kalan kısmında yeni bir div
oluşturuyoruz. Daha sonra iç HTML'sini daha önce tanımladığımız textCont()
işlevinin çıktısı olacak şekilde ayarladık. Son olarak, ona bir sınıf ekliyoruz (stil için) ve onu sonuç konteynerine ekliyoruz. Bunun etkisi, her hesaplamanın bir öncekinin altında ayrı bir div
görünmesidir.

Sayı arttıkça hesaplama süresinin de (üssel olarak) arttığını görebiliriz. Örneğin, 30'dan 35'e, hesaplama zamanını 13ms'den 130ms'ye atladık. Bu operasyonları hala “hızlı” olarak değerlendirebiliriz. 40'ta 1 saniyenin üzerinde bir hesaplama süresi görüyoruz. Makinemde, sayfanın yanıt vermediğini fark etmeye başladığım yer burası. Bu noktada, hesaplama devam ederken artık sayfa ile etkileşime giremiyorum. Girdiye odaklanamıyorum veya başka bir şey yapamıyorum.
JavaScript'in tek iş parçacıklı olduğundan bahsettiğimizi hatırlıyor musunuz? Eh, bu iş parçacığı bu uzun süredir devam eden hesaplama tarafından "engellendi", bu yüzden diğer her şeyin bitmesini "beklemesi" gerekiyor. Makinenizde daha düşük veya daha yüksek bir değerde başlayabilir, ancak o noktaya ulaşmak zorundasınız. 44'ü hesaplamanın neredeyse 10 saniye sürdüğüne dikkat edin. Web uygulamanızda yapılacak başka şeyler varsa, kullanıcının devam edebilmesi için Fib(44)'ün bitmesini beklemesi gerekir. Ancak bu hesaplamayı yapmak için bir web çalışanı görevlendirdiyseniz, kullanıcılarınız bu çalışırken başka bir şeyle devam edebilir.

Şimdi web çalışanlarının bu sorunun üstesinden gelmemize nasıl yardımcı olduğunu görelim.
Örnek Bir Web Çalışanı İş Başında
Bu bölümde, n'inci FN'yi hesaplama işini bir web çalışanına devredeceğiz. Bu, ana iş parçacığını boşaltmaya ve hesaplama devam ederken kullanıcı arayüzümüzün yanıt vermesini sağlamaya yardımcı olacaktır.
Web çalışanları ile başlamak şaşırtıcı derecede basittir. Nasıl olduğunu görelim. Yeni bir dosya src/fib-worker.js
. ve aşağıdaki kodu girin.
const fib = (n) => (n < 2 ? n : fib(n - 1) + fib(n - 2)); onmessage = (e) => { const { num } = e.data; const startTime = new Date().getTime(); const fibNum = fib(num); postMessage({ fibNum, time: new Date().getTime() - startTime, }); };
n'inci Fibonacci sayısını hesaplayan fonksiyonu, fib
bu dosyanın içine taşıdığımıza dikkat edin. Bu dosya web çalışanımız tarafından çalıştırılacaktır.
Web işçisi nedir bölümünde hatırlayın, web çalışanlarının ve üstlerinin onmessage
olay işleyicisini ve postMessage postMessage()
yöntemini kullanarak iletişim kurduklarından bahsettik. Burada, ana komut dosyasındaki mesajları dinlemek için onmessage
olay işleyicisini kullanıyoruz. Bir mesaj aldığımızda, olayın data özniteliğinden sayıyı yok ederiz. Ardından, geçerli saati alır ve hesaplamaya başlarız. Sonuç hazır olduğunda, sonuçları ana komut dosyasına geri göndermek için postMessage()
yöntemini kullanırız.
src/index.js
açın, bazı değişiklikler yapalım.
... const worker = new window.Worker("src/fib-worker.js"); btn.addEventListener("click", (e) => { errPar.textContent = ""; const num = window.Number(input.value); if (num < 2) { errPar.textContent = "Please enter a number greater than 2"; return; } worker.postMessage({ num }); worker.onerror = (err) => err; worker.onmessage = (e) => { const { time, fibNum } = e.data; const resultDiv = document.createElement("div"); resultDiv.innerHTML = textCont(num, fibNum, time); resultDiv.className = "result-div"; resultsContainer.appendChild(resultDiv); }; });
Yapılacak ilk şey, Worker
yapıcısını kullanarak web işçisini oluşturmaktır. Ardından, düğmemizin olay dinleyicisinin içinde, worker.postMessage({ num })
kullanarak çalışana bir sayı göndeririz. Bundan sonra, işçideki hataları dinleyecek bir fonksiyon belirledik. Burada sadece hatayı döndürüyoruz. İsterseniz kesinlikle DOM'da göstermek gibi daha fazlasını yapabilirsiniz. Ardından, çalışandan gelen mesajları dinliyoruz. Bir mesaj aldığımızda, time
ve fibNum
yok edip DOM'da gösterme işlemine devam ediyoruz.
Web işçisinin içinde, onmessage
olayının işçinin kapsamında mevcut olduğuna dikkat edin, bu yüzden onu self.onmessage
ve self.postMessage()
olarak yazabilirdik. Ancak ana komut dosyasında bunları çalışanın kendisine eklememiz gerekir.
Aşağıdaki ekran görüntüsünde, Chrome Geliştirme Araçları'nın kaynaklar sekmesinde web çalışanı dosyasını görürsünüz. Fark etmeniz gereken şey, hangi numarayı girerseniz girin kullanıcı arayüzünün duyarlı kalmasıdır. Bu davranış, web çalışanlarının büyüsüdür.

Web uygulamamızla çok ilerleme kaydettik. Ama daha iyi hale getirmek için yapabileceğimiz başka bir şey var. Mevcut uygulamamız, her hesaplamayı işlemek için tek bir çalışan kullanır. Biri çalışırken yeni bir mesaj gelirse, eskisi değiştirilir. Bunu aşmak için, FN'yi hesaplamak için her çağrı için yeni bir çalışan oluşturabiliriz. Bunu nasıl yapacağımızı bir sonraki bölümde görelim.
Birden Çok Web Çalışanıyla Çalışmak
Şu anda her talebi tek bir çalışanla ele alıyoruz. Böylece gelen bir istek, henüz tamamlanmamış olan bir öncekinin yerini alacaktır. Şimdi istediğimiz şey, her istek için yeni bir web çalışanı oluşturmak için küçük bir değişiklik yapmak. İşi bitince bu işçiyi öldüreceğiz.
src/index.js
açın ve web çalışanını oluşturan satırı düğmenin click olay işleyicisinin içine taşıyın. Şimdi olay işleyicisi aşağıdaki gibi görünmelidir.
btn.addEventListener("click", (e) => { errPar.textContent = ""; const num = window.Number(input.value); if (num < 2) { errPar.textContent = "Please enter a number greater than 2"; return; } const worker = new window.Worker("src/fib-worker.js"); // this line has moved inside the event handler worker.postMessage({ num }); worker.onerror = (err) => err; worker.onmessage = (e) => { const { time, fibNum } = e.data; const resultDiv = document.createElement("div"); resultDiv.innerHTML = textCont(num, fibNum, time); resultDiv.className = "result-div"; resultsContainer.appendChild(resultDiv); worker.terminate() // this line terminates the worker }; });
İki değişiklik yaptık.
- Bu satırı
const worker = new window.Worker("src/fib-worker.js")
düğmesinin click olay işleyicisinin içine taşıdık. - İşimiz bittiğinde işçiyi atmak için bu satırı
worker.terminate()
olarak ekledik.
Bu nedenle, düğmenin her tıklaması için hesaplamayı yapmak için yeni bir işçi oluşturuyoruz. Böylece girdiyi değiştirmeye devam edebiliriz ve hesaplama bittiğinde her sonuç ekrana gelecektir. Aşağıdaki ekran görüntüsünde 20 ve 30 değerlerinin 45'ten önce geldiğini görebilirsiniz. Ama önce 45'e başladım. İşlev 20 ve 30 için döndüğünde sonuçları gönderildi ve çalışan sonlandırıldı. Her şey bittiğinde, kaynaklar sekmesinde herhangi bir çalışanımız olmamalıdır.

Bu makaleyi burada bitirebiliriz, ancak bu bir tepki uygulaması olsaydı, web çalışanlarını buna nasıl dahil ederdik. Bir sonraki bölümün odak noktası budur.
Tepkideki Web Çalışanları
Başlamak için CRA'yı kullanarak yeni bir tepki uygulaması oluşturun. fib-worker.js
dosyasını tepki uygulamanızın public/
klasörüne kopyalayın. Dosyayı buraya koymak, React uygulamalarının tek sayfalık uygulamalar olduğu gerçeğinden kaynaklanmaktadır. Çalışanı bir tepki uygulamasında kullanmaya özgü olan tek şey budur. Buradan çıkan her şey saf React'tir.
src/
klasöründe bir helpers.js
dosyası oluşturun ve ordinal_suffix()
işlevini bu dosyadan dışa aktarın.
// src/helpers.js export const ordinal_suffix = (num) => { // 1st, 2nd, 3rd, 4th, etc. const j = num % 10; const k = num % 100; switch (true) { case j === 1 && k !== 11: return num + "st"; case j === 2 && k !== 12: return num + "nd"; case j === 3 && k !== 13: return num + "rd"; default: return num + "th"; } };
Uygulamamız bir durumu korumamızı gerektirecek, bu nedenle başka bir dosya, src/reducer.js
oluşturun ve durum düşürücüye yapıştırın.
// src/reducers.js export const reducer = (state = {}, action) => { switch (action.type) { case "SET_ERROR": return { ...state, err: action.err }; case "SET_NUMBER": return { ...state, num: action.num }; case "SET_FIBO": return { ...state, computedFibs: [ ...state.computedFibs, { id: action.id, nth: action.nth, loading: action.loading }, ], }; case "UPDATE_FIBO": { const curr = state.computedFibs.filter((c) => c.id === action.id)[0]; const idx = state.computedFibs.indexOf(curr); curr.loading = false; curr.time = action.time; curr.fibNum = action.fibNum; state.computedFibs[idx] = curr; return { ...state }; } default: return state; } };
Her eylem türünü birbiri ardına inceleyelim.
-
SET_ERROR
: tetiklendiğinde bir hata durumu ayarlar. -
SET_NUMBER
: Giriş kutumuzdaki değeri durum olarak ayarlar. -
SET_FIBO
: hesaplanan FN dizisine yeni bir giriş ekler. -
UPDATE_FIBO
: burada belirli bir girişi ararız ve onu hesaplanan FN'ye ve onu hesaplamak için geçen zamana sahip yeni bir nesneyle değiştiririz.
Bu redüktörü birazdan kullanacağız. Ondan önce, hesaplanan FN'leri gösterecek bileşeni oluşturalım. Yeni bir src/Results.js
dosyası oluşturun ve aşağıdaki kodu yapıştırın.
// src/Results.js import React from "react"; export const Results = (props) => { const { results } = props; return ( <div className="results-container"> {results.map((fb) => { const { id, nth, time, fibNum, loading } = fb; return ( <div key={id} className="result-div"> {loading ? ( <p> Calculating the{" "} <span className="bold"> {nth} </span>{" "} Fibonacci number... </p> ) : ( <> <p> Time: <span className="bold">{time} ms</span> </p> <p> <span className="bold"> {nth} </span>{" "} fibonnaci number:{" "} <span className="bold"> {fibNum} </span> </p> </> )} </div> ); })} </div> ); };
Bu değişiklik ile bir önceki index.html dosyamızı jsx'e dönüştürme işlemine başlıyoruz. Bu dosyanın bir sorumluluğu vardır: hesaplanan FN'leri temsil eden bir dizi nesneyi alın ve bunları görüntüleyin. Daha önce sahip olduğumuzdan tek fark, bir yükleme durumunun tanıtılmasıdır. Şimdi, hesaplama çalışırken, kullanıcıya bir şeyler olduğunu bildirmek için yükleme durumunu gösteriyoruz.
src/App.js
içindeki kodu güncelleyerek son parçaları koyalım. Kod oldukça uzun, bu yüzden iki adımda yapacağız. İlk kod bloğunu ekleyelim.
import React from "react"; import "./App.css"; import { ordinal_suffix } from "./helpers"; import { reducer } from './reducer' import { Results } from "./Results"; function App() { const [info, dispatch] = React.useReducer(reducer, { err: "", num: "", computedFibs: [], }); const runWorker = (num, id) => { dispatch({ type: "SET_ERROR", err: "" }); const worker = new window.Worker('./fib-worker.js') worker.postMessage({ num }); worker.onerror = (err) => err; worker.onmessage = (e) => { const { time, fibNum } = e.data; dispatch({ type: "UPDATE_FIBO", id, time, fibNum, }); worker.terminate(); }; }; return ( <div> <div className="heading-container"> <h1>Computing the nth Fibonnaci number</h1> </div> <div className="body-container"> <p className="error"> {info.err} </p> // ... next block of code goes here ... // <Results results={info.computedFibs} /> </div> </div> ); } export default App;
Her zamanki gibi ithalatımızı getiriyoruz. Ardından useReducer kancasıyla bir durum ve güncelleyici işlevi başlatırız. Ardından, bir sayı ve bir kimlik alan ve bu numara için FN'yi hesaplamak üzere bir web çalışanını çağırmayı ayarlayan runWorker()
bir işlev tanımlarız.
Çalışanı oluşturmak için, çalışan yapıcısına göreli bir yol ilettiğimizi unutmayın. Çalışma zamanında, React kodumuz public/index.html
dosyasına eklenir, böylece fib-worker.js
dosyasını aynı dizinde bulabilir. Hesaplama tamamlandığında ( worker.onmessage
tarafından tetiklenir), UPDATE_FIBO
eylemi gönderilir ve çalışan daha sonra sonlandırılır. Şimdi sahip olduğumuz şey, daha önce sahip olduğumuzdan çok farklı değil.
Bu bileşenin dönüş bloğunda, daha önce sahip olduğumuz HTML'nin aynısını oluşturuyoruz. Ayrıca, işleme için hesaplanan sayılar dizisini <Results />
bileşenine iletiriz.
Son kod bloğunu return
ifadesinin içine ekleyelim.
<div className="input-div"> <input type="number" value={info.num} className="number-input" placeholder="Enter a number" onChange={(e) => dispatch({ type: "SET_NUMBER", num: window.Number(e.target.value), }) } /> <button className="btn-submit" onClick={() => { if (info.num < 2) { dispatch({ type: "SET_ERROR", err: "Please enter a number greater than 2", }); return; } const id = info.computedFibs.length; dispatch({ type: "SET_FIBO", id, loading: true, nth: ordinal_suffix(info.num), }); runWorker(info.num, id); }} > Calculate </button> </div>
info.num
durum değişkenini güncellemek için girişte bir onChange
işleyicisi ayarladık. Buton üzerinde bir onClick
olay işleyicisi tanımlıyoruz. Düğme tıklandığında, sayının 2'den büyük olup olmadığını kontrol ederiz. runWorker()
çağırmadan önce, hesaplanan FN'ler dizisine bir giriş eklemek için ilk önce bir eylem gönderdiğimize dikkat edin. Çalışan işini bitirdiğinde güncellenecek olan bu giriştir. Bu şekilde, her giriş, daha önce sahip olduğumuzdan farklı olarak listedeki konumunu korur.
Son olarak, App.css
styles.css
değiştirin.
Artık her şey yerli yerinde. Şimdi tepki sunucunuzu başlatın ve bazı sayılarla oynayın. Bir UX iyileştirmesi olan yükleme durumuna dikkat edin. Ayrıca, 1000 gibi yüksek bir sayı girip "Hesapla"yı tıkladığınızda bile kullanıcı arayüzünün yanıt vermeye devam ettiğini unutmayın.

Yükleme durumunu ve aktif çalışanı not edin. 46. değer hesaplandıktan sonra işçi öldürülür ve yükleme durumu nihai sonuçla değiştirilir.
- Bu React uygulamasının kaynak kodu Github'da mevcut ve vercel'de barındırılan bir uygulama var.
Çözüm
Vay! Uzun bir yolculuk oldu, o yüzden bitirelim. Web çalışanlarını kullanmanın diğer yollarını öğrenmek için web çalışanları için MDN girişine (aşağıdaki kaynaklar listesine bakın) bir göz atmanızı tavsiye ederim.
Bu makalede, web çalışanlarının ne olduğunu ve çözmeleri gereken sorun türlerini öğrendik. Düz JavaScript kullanarak bunları nasıl uygulayacağımızı da gördük. Son olarak, bir React uygulamasında web çalışanlarının nasıl uygulanacağını gördük.
Kullanıcılarınıza daha iyi bir deneyim sunmak için bu harika API'den yararlanmanızı tavsiye ederim.
Diğer Kaynaklar
-
Console.time()
, MDN web belgeleri - {JSON} Yer tutucu, resmi web sitesi
- Web Çalışanlarını, MDN web belgelerini kullanma
- Fibonacci sayısı, Vikipedi
- Koşullu (üçlü) operatör, MDN web belgeleri
-
Document
, Web API'leri, MDN web belgeleri - Başlarken, React Uygulaması Oluşturun (belgeler)
-
Function.prototype.toString()
, MDN web belgeleri - IIFE, MDN web belgeleri
-
workerSetup.js
, Harika Fullstack Eğitimleri, GitHub - “Web Çalışanlarını Kullanarak JavaScript'te Paralel Programlama,” Uday Hiwarale, Medium