Mengelola Tugas yang Berjalan Lama Dalam Aplikasi React Dengan Web Worker

Diterbitkan: 2022-03-10
Ringkasan cepat Dalam tutorial ini, kita akan mempelajari cara menggunakan Web Worker API untuk mengelola tugas yang memakan waktu dan pemblokiran UI dalam aplikasi JavaScript dengan membuat contoh aplikasi web yang memanfaatkan Web Worker. Terakhir, kita akan mengakhiri artikel dengan mentransfer semuanya ke aplikasi React.

Waktu respons adalah masalah besar dalam hal aplikasi web. Pengguna menuntut respons instan, apa pun yang dilakukan aplikasi Anda. Baik itu hanya menampilkan nama seseorang atau menghitung angka, pengguna aplikasi web menuntut agar aplikasi Anda merespons perintah mereka setiap saat. Terkadang hal itu sulit dicapai mengingat sifat JavaScript yang berulir tunggal. Namun dalam artikel ini, kita akan mempelajari bagaimana kita dapat memanfaatkan Web Worker API untuk memberikan pengalaman yang lebih baik.

Dalam menulis artikel ini, saya membuat asumsi berikut:

  1. Untuk dapat mengikuti, Anda harus memiliki setidaknya beberapa keakraban dengan JavaScript dan API dokumen;
  2. Anda juga harus memiliki pengetahuan tentang React sehingga Anda dapat berhasil memulai proyek React baru menggunakan Create React App.

Jika Anda membutuhkan lebih banyak wawasan tentang topik ini, saya telah menyertakan sejumlah tautan di bagian "Sumber Daya Lebih Lanjut" untuk membantu Anda mendapatkan informasi terbaru.

Pertama, mari kita mulai dengan Pekerja Web.

Apa itu Pekerja Web?

Untuk memahami Pekerja Web dan masalah yang ingin mereka pecahkan, penting untuk memahami bagaimana kode JavaScript dieksekusi saat runtime. Selama runtime, kode JavaScript dieksekusi secara berurutan dan secara belokan demi belokan. Setelah sepotong kode berakhir, maka yang berikutnya dalam baris mulai berjalan, dan seterusnya. Dalam istilah teknis, kami mengatakan bahwa JavaScript adalah single-threaded. Perilaku ini menyiratkan bahwa setelah beberapa bagian kode mulai berjalan, setiap kode yang muncul setelahnya harus menunggu kode tersebut untuk menyelesaikan eksekusi. Jadi, setiap baris kode "memblokir" eksekusi segala sesuatu yang datang setelahnya. Oleh karena itu, diinginkan agar setiap bagian kode selesai secepat mungkin. Jika beberapa bagian kode membutuhkan waktu terlalu lama untuk menyelesaikannya, program kami akan tampak berhenti bekerja. Di browser, ini bermanifestasi sebagai halaman yang beku dan tidak responsif. Dalam beberapa kasus ekstrim, tab akan membeku sama sekali.

Bayangkan mengemudi di satu jalur. Jika salah satu pengemudi di depan Anda berhenti bergerak karena alasan apa pun, maka Anda mengalami kemacetan lalu lintas. Dengan program seperti Java, lalu lintas bisa berlanjut di jalur lain. Jadi Java dikatakan multi-threaded. Pekerja Web adalah upaya untuk membawa perilaku multi-utas ke JavaScript.

Tangkapan layar di bawah ini menunjukkan bahwa Web Worker API didukung oleh banyak browser, jadi Anda harus merasa percaya diri dalam menggunakannya.

Menampilkan bagan dukungan browser untuk pekerja web
Dukungan browser Web Worker. (Pratinjau besar)

Pekerja Web berjalan di utas latar belakang tanpa mengganggu UI, dan mereka berkomunikasi dengan kode yang membuatnya melalui pengendali peristiwa.

Definisi yang sangat baik dari Web Worker berasal dari MDN:

“Pekerja adalah objek yang dibuat menggunakan konstruktor (mis Worker() yang menjalankan file JavaScript bernama — file ini berisi kode yang akan dijalankan di thread pekerja; pekerja dijalankan dalam konteks global lain yang berbeda dari window saat ini. Jadi, , menggunakan pintasan window untuk mendapatkan cakupan global saat ini (bukan self dalam Worker akan mengembalikan kesalahan.”

Worker dibuat menggunakan konstruktor Worker .

 const worker = new Worker('worker-file.js')

Dimungkinkan untuk menjalankan sebagian besar kode di dalam pekerja web, dengan beberapa pengecualian. Misalnya, Anda tidak dapat memanipulasi DOM dari dalam pekerja. Tidak ada akses ke API document .

Pekerja dan utas yang memunculkan mereka mengirim pesan satu sama lain menggunakan metode postMessage() . Demikian pula, mereka merespons pesan menggunakan event handler onmessage . Sangat penting untuk mendapatkan perbedaan ini. Mengirim pesan dicapai dengan menggunakan metode; menerima pesan kembali membutuhkan event handler. Pesan yang diterima terkandung dalam atribut data acara. Kita akan melihat contohnya di bagian selanjutnya. Namun izinkan saya segera menyebutkan bahwa jenis pekerja yang telah kita diskusikan disebut "pekerja yang berdedikasi". Ini berarti bahwa pekerja hanya dapat diakses oleh skrip yang memanggilnya. Dimungkinkan juga untuk memiliki pekerja yang dapat diakses dari beberapa skrip. Ini disebut pekerja bersama dan dibuat menggunakan konstruktor SharedWorker , seperti yang ditunjukkan di bawah ini.

 const sWorker = new SharedWorker('shared-worker-file.js')

Untuk mempelajari lebih lanjut tentang Pekerja, silakan lihat artikel MDN ini. Tujuan artikel ini adalah untuk membantu Anda mulai menggunakan pekerja Web. Mari kita mulai dengan menghitung angka Fibonacci ke-n.

Lebih banyak setelah melompat! Lanjutkan membaca di bawah ini

Menghitung Angka Fibonacci Ke-N

Catatan: Untuk bagian ini dan dua bagian berikutnya, saya menggunakan Live Server di VSCode untuk menjalankan aplikasi. Anda pasti dapat menggunakan sesuatu yang lain.

Ini adalah bagian yang Anda tunggu-tunggu. Kami akhirnya akan menulis beberapa kode untuk melihat Pekerja Web beraksi. Yah, tidak begitu cepat. Kami tidak akan menghargai pekerjaan yang dilakukan Web Worker kecuali kami mengalami masalah yang dipecahkannya. Di bagian ini, kita akan melihat contoh masalah, dan di bagian berikutnya, kita akan melihat bagaimana pekerja web membantu kita melakukan lebih baik.

Bayangkan Anda sedang membangun aplikasi web yang memungkinkan pengguna menghitung angka Fibonacci ke-n. Jika Anda baru mengenal istilah 'bilangan Fibonacci', Anda dapat membacanya lebih lanjut di sini, tetapi secara ringkas, angka Fibonacci adalah urutan angka sehingga setiap angka adalah jumlah dari dua angka sebelumnya.

Secara matematis, dinyatakan sebagai:

Jadi beberapa bilangan pertama dari barisan tersebut adalah:

1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 ...

Dalam beberapa sumber, urutannya dimulai dari F 0 = 0 , dalam hal ini rumus di bawah ini berlaku untuk n > 1 :

Pada artikel ini kita akan mulai dari F 1 = 1. Satu hal yang dapat kita lihat langsung dari rumus adalah bahwa bilangan mengikuti pola rekursif. Tugas yang ada sekarang adalah menulis fungsi rekursif untuk menghitung bilangan Fibonacci (FN) ke-n.

Setelah beberapa kali mencoba, saya yakin Anda dapat dengan mudah menemukan fungsi di bawah ini.

 const fib = n => { if (n < 2) { return n // or 1 } else { return fib(n - 1) + fib(n - 2) } }

Fungsinya sederhana. Jika n kurang dari 2, kembalikan n (atau 1), jika tidak, kembalikan jumlah n-1 dan n-2 FN. Dengan fungsi panah dan operator ternary, kita dapat membuat one-liner.

 const fib = n => (n < 2 ? n : fib(n-1) + fib(n-2))

Fungsi ini memiliki kompleksitas waktu 0(2 n ) . Ini berarti bahwa ketika nilai n meningkat, waktu yang dibutuhkan untuk menghitung jumlah meningkat secara eksponensial. Ini membuat tugas berjalan sangat lama yang berpotensi mengganggu UI kami, untuk nilai n yang besar. Mari kita lihat ini dalam tindakan.

Catatan : Ini sama sekali bukan cara terbaik untuk menyelesaikan masalah khusus ini. Pilihan saya untuk menggunakan metode ini adalah untuk tujuan artikel ini.

Untuk memulai, buat folder baru dan beri nama apa pun yang Anda suka. Sekarang di dalam folder itu buat folder src/ . Juga, buat file index.html di folder root. Di dalam folder src/ , buat file bernama index.js .

Buka index.html dan tambahkan kode HTML berikut.

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

Bagian ini sangat sederhana. Pertama, kita memiliki heading. Kemudian kami memiliki wadah dengan input dan tombol. Seorang pengguna akan memasukkan nomor kemudian klik "Hitung". Kami juga memiliki wadah untuk menampung hasil perhitungan. Terakhir, kami menyertakan file src/index.js dalam tag script .

Anda dapat menghapus tautan stylesheet. Tetapi jika Anda kekurangan waktu, saya telah menetapkan beberapa CSS yang dapat Anda gunakan. Cukup buat file styles.css di folder root dan tambahkan gaya di bawah ini:

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

Sekarang buka src/index.js mari kita kembangkan secara perlahan. Tambahkan kode di bawah ini.

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

Di sini kita memiliki tiga fungsi. Yang pertama adalah fungsi yang kita lihat sebelumnya untuk menghitung FN ke-n. Fungsi kedua hanyalah fungsi utilitas untuk melampirkan sufiks yang sesuai ke bilangan bulat. Fungsi ketiga mengambil beberapa argumen dan mengeluarkan markup yang nantinya akan kita sisipkan di DOM. Argumen pertama adalah angka yang FN-nya sedang dihitung. Argumen kedua adalah FN yang dihitung. Argumen terakhir adalah waktu yang dibutuhkan untuk melakukan komputasi.

Masih di src/index.js , tambahkan kode di bawah ini tepat di bawah kode sebelumnya.

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

Pertama, kami menggunakan API document untuk mendapatkan node DOM di file HTML kami. Kami mendapatkan referensi ke paragraf di mana kami akan menampilkan pesan kesalahan; masukan; tombol hitung dan wadah tempat kami akan menampilkan hasil kami.

Selanjutnya, kita lampirkan event handler “klik” ke tombol. Ketika tombol diklik, kami mengambil apa pun yang ada di dalam elemen input dan mengubahnya menjadi angka, jika kami mendapatkan yang kurang dari 2, kami menampilkan pesan kesalahan dan kembali. Jika kami mendapatkan angka yang lebih besar dari 2, kami melanjutkan. Pertama, kami mencatat waktu saat ini. Setelah itu, kami menghitung FN. Ketika itu selesai, kami mendapatkan perbedaan waktu yang mewakili berapa lama waktu yang dibutuhkan untuk menghitung. Di bagian kode yang tersisa, kami membuat div baru. Kami kemudian mengatur HTML bagian dalamnya menjadi output dari fungsi textCont() yang kami definisikan sebelumnya. Terakhir, kami menambahkan kelas ke dalamnya (untuk penataan gaya) dan menambahkannya ke wadah hasil. Efeknya adalah bahwa setiap perhitungan akan muncul di div terpisah di bawah div sebelumnya.

Menampilkan angka Fibonacci yang dihitung hingga 43
Beberapa angka Fibonacci. (Pratinjau besar)

Kita dapat melihat bahwa dengan bertambahnya jumlah, waktu komputasi juga meningkat (secara eksponensial). Misalnya, dari 30 ke 35, kami mengalami lompatan waktu komputasi dari 13 md ke 130 md. Kami masih dapat menganggap operasi itu "cepat". Pada 40 kita melihat waktu komputasi lebih dari 1 detik. Di komputer saya, di sinilah saya mulai melihat halaman menjadi tidak responsif. Pada titik ini, saya tidak dapat lagi berinteraksi dengan halaman saat penghitungan sedang berlangsung. Saya tidak bisa fokus pada input atau melakukan hal lain.

Ingat ketika kita berbicara tentang JavaScript menjadi single-threaded? Nah, utas itu telah "diblokir" oleh perhitungan yang sudah berjalan lama ini, jadi yang lainnya harus "menunggu" sampai selesai. Ini mungkin dimulai pada nilai yang lebih rendah atau lebih tinggi pada mesin Anda, tetapi Anda pasti akan mencapai titik itu. Perhatikan bahwa dibutuhkan waktu hampir 10 detik untuk menghitung 44. Jika ada hal lain yang harus dilakukan di aplikasi web Anda, pengguna harus menunggu Fib(44) selesai sebelum mereka dapat melanjutkan. Tetapi jika Anda menggunakan pekerja web untuk menangani perhitungan itu, pengguna Anda dapat melanjutkan dengan sesuatu yang lain saat itu berjalan.

Sekarang mari kita lihat bagaimana pekerja web membantu kita mengatasi masalah ini.

Contoh Kerja Web Worker

Di bagian ini, kami akan mendelegasikan tugas menghitung FN ke-n ke pekerja web. Ini akan membantu membebaskan utas utama dan menjaga UI kami tetap responsif saat komputasi sedang berlangsung.

Memulai dengan pekerja web ternyata sangat sederhana. Mari kita lihat bagaimana. Buat file baru src/fib-worker.js . dan masukkan kode berikut.

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

Perhatikan bahwa kita telah memindahkan fungsi yang menghitung bilangan Fibonacci ke-n, fib di dalam file ini. File ini akan dijalankan oleh pekerja web kami.

Ingat di bagian Apa itu pekerja web , kami menyebutkan bahwa pekerja web dan induknya berkomunikasi menggunakan event handler onmessage dan metode postMessage() . Di sini kita menggunakan event handler onmessage untuk mendengarkan pesan dari skrip induk. Setelah kami mendapatkan pesan, kami merusak nomor dari atribut data acara. Selanjutnya, kita mendapatkan waktu saat ini dan memulai perhitungan. Setelah hasilnya siap, kami menggunakan metode postMessage() untuk memposting hasilnya kembali ke skrip induk.

Buka src/index.js mari kita buat beberapa perubahan.

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

Hal pertama yang harus dilakukan adalah membuat pekerja web menggunakan konstruktor Worker . Kemudian di dalam pendengar acara tombol kami, kami mengirim nomor ke pekerja menggunakan worker.postMessage({ num }) . Setelah itu, kami menetapkan fungsi untuk mendengarkan kesalahan pada pekerja. Di sini kita cukup mengembalikan kesalahan. Anda pasti dapat melakukan lebih banyak jika Anda mau, seperti menampilkannya di DOM. Selanjutnya, kami mendengarkan pesan dari pekerja. Setelah kami mendapatkan pesan, kami merusak time dan fibNum , dan melanjutkan proses menampilkannya di DOM.

Perhatikan bahwa di dalam pekerja web, acara onmessage tersedia dalam lingkup pekerja, jadi kita bisa menulisnya sebagai self.onmessage dan self.postMessage() . Tetapi dalam skrip induk, kita harus melampirkan ini ke pekerja itu sendiri.

Pada tangkapan layar di bawah, Anda akan melihat file pekerja web di tab sumber Alat Pengembang Chrome. Apa yang harus Anda perhatikan adalah bahwa UI tetap responsif tidak peduli nomor apa yang Anda masukkan. Perilaku ini adalah keajaiban pekerja web.

Tampilan file pekerja web aktif
File pekerja web yang sedang berjalan. (Pratinjau besar)

Kami telah membuat banyak kemajuan dengan aplikasi web kami. Tapi ada hal lain yang bisa kita lakukan untuk membuatnya lebih baik. Implementasi kami saat ini menggunakan satu pekerja untuk menangani setiap komputasi. Jika pesan baru datang saat salah satu sedang berjalan, yang lama akan diganti. Untuk menyiasatinya, kita dapat membuat pekerja baru untuk setiap panggilan untuk menghitung FN. Mari kita lihat bagaimana melakukannya di bagian selanjutnya.

Bekerja Dengan Banyak Pekerja Web

Saat ini, kami menangani setiap permintaan dengan satu pekerja. Dengan demikian permintaan yang masuk akan menggantikan permintaan sebelumnya yang belum selesai. Yang kami inginkan sekarang adalah membuat perubahan kecil untuk menelurkan pekerja web baru untuk setiap permintaan. Kami akan membunuh pekerja ini setelah selesai.

Buka src/index.js dan pindahkan baris yang membuat web worker di dalam event handler klik tombol. Sekarang event handler akan terlihat seperti di bawah ini.

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

Kami membuat dua perubahan.

  1. Kami memindahkan baris ini const worker = new window.Worker("src/fib-worker.js") di dalam event handler klik tombol.
  2. Kami menambahkan baris worker.terminate() ini untuk membuang pekerja setelah kami selesai melakukannya.

Jadi untuk setiap klik tombol, kami membuat pekerja baru untuk menangani perhitungan. Dengan demikian kita dapat terus mengubah input, dan setiap hasil akan muncul di layar setelah perhitungan selesai. Pada tangkapan layar di bawah ini Anda dapat melihat bahwa nilai untuk 20 dan 30 muncul sebelum nilai 45. Tapi saya memulai 45 terlebih dahulu. Setelah fungsi kembali untuk 20 dan 30, hasilnya diposting, dan pekerja dihentikan. Ketika semuanya selesai, kita seharusnya tidak memiliki pekerja di tab sumber.

menunjukkan angka Fibonacci dengan pekerja yang diberhentikan
Ilustrasi Beberapa pekerja independen. (Pratinjau besar)

Kami dapat mengakhiri artikel ini di sini, tetapi jika ini adalah aplikasi reaksi, bagaimana kami akan membawa pekerja web ke dalamnya. Itulah fokus dari bagian selanjutnya.

Pekerja Web Dalam Bereaksi

Untuk memulai, buat aplikasi reaksi baru menggunakan CRA. Salin file fib-worker.js ke folder public/ aplikasi reaksi Anda. Menempatkan file di sini berasal dari fakta bahwa aplikasi React adalah aplikasi satu halaman. Itu tentang satu-satunya hal yang khusus untuk menggunakan pekerja dalam aplikasi reaksi. Segala sesuatu yang mengikuti dari sini adalah React murni.

Di folder src/ buat file helpers.js dan ekspor fungsi ordinal_suffix() darinya.

 // 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"; } };

Aplikasi kita akan mengharuskan kita untuk mempertahankan beberapa status, jadi buat file lain, src/reducer.js dan tempel di peredam status.

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

Mari kita bahas setiap jenis tindakan satu demi satu.

  1. SET_ERROR : menetapkan status kesalahan saat dipicu.
  2. SET_NUMBER : menyetel nilai di kotak input kami ke status.
  3. SET_FIBO : menambahkan entri baru ke larik FN yang dihitung.
  4. UPDATE_FIBO : di sini kita mencari entri tertentu dan menggantinya dengan objek baru yang memiliki FN yang dihitung dan waktu yang dibutuhkan untuk menghitungnya.

Kami akan segera menggunakan peredam ini. Sebelum itu, mari buat komponen yang akan menampilkan FN yang dihitung. Buat file baru src/Results.js dan rekatkan kode di bawah ini.

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

Dengan perubahan ini, kami memulai proses mengonversi file index.html kami sebelumnya ke jsx. File ini memiliki satu tanggung jawab: mengambil array objek yang mewakili FN yang dihitung dan menampilkannya. Satu-satunya perbedaan dari apa yang kami miliki sebelumnya adalah pengenalan status pemuatan . Jadi sekarang saat komputasi sedang berjalan, kami menunjukkan status pemuatan untuk memberi tahu pengguna bahwa ada sesuatu yang terjadi.

Mari kita masukkan bagian terakhir dengan memperbarui kode di dalam src/App.js . Kodenya agak panjang, jadi kita akan melakukannya dalam dua langkah. Mari tambahkan blok kode pertama.

 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;

Seperti biasa, kami membawa impor kami. Kemudian kita membuat instance fungsi state dan updater dengan hook useReducer. Kami kemudian mendefinisikan fungsi, runWorker() , yang mengambil nomor dan ID dan menetapkan tentang memanggil pekerja web untuk menghitung FN untuk nomor itu.

Perhatikan bahwa untuk membuat pekerja, kami melewati jalur relatif ke konstruktor pekerja. Saat runtime, kode React kita dilampirkan ke file public/index.html , sehingga ia dapat menemukan file fib-worker.js di direktori yang sama. Saat penghitungan selesai (dipicu oleh worker.onmessage ), tindakan UPDATE_FIBO dikirim, dan pekerja dihentikan setelahnya. Apa yang kita miliki sekarang tidak jauh berbeda dengan apa yang kita miliki sebelumnya.

Di blok pengembalian komponen ini, kami merender HTML yang sama seperti sebelumnya. Kami juga meneruskan array angka yang dihitung ke komponen <Results /> untuk rendering.

Mari tambahkan blok kode terakhir di dalam pernyataan return .

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

Kami menetapkan handler onChange pada input untuk memperbarui variabel status info.num . Pada tombol tersebut, kita mendefinisikan event handler onClick . Saat tombol diklik, kami memeriksa apakah angkanya lebih besar dari 2. Perhatikan bahwa sebelum memanggil runWorker() , kami terlebih dahulu mengirimkan tindakan untuk menambahkan entri ke larik FN yang dihitung. Entri inilah yang akan diperbarui setelah pekerja menyelesaikan pekerjaannya. Dengan cara ini, setiap entri mempertahankan posisinya dalam daftar, tidak seperti yang kami miliki sebelumnya.

Terakhir, salin konten styles.css dari sebelumnya dan ganti konten App.css .

Kami sekarang memiliki segalanya di tempat. Sekarang mulai server reaksi Anda dan mainkan dengan beberapa angka. Perhatikan status pemuatan, yang merupakan peningkatan UX. Juga, perhatikan bahwa UI tetap responsif bahkan ketika Anda memasukkan angka setinggi 1000 dan klik "Hitung".

menunjukkan status pemuatan saat pekerja aktif.
Menampilkan status pemuatan dan pekerja web aktif. (Pratinjau besar)

Perhatikan status pemuatan dan pekerja aktif. Setelah nilai ke-46 dihitung, pekerja dibunuh dan status pemuatan diganti dengan hasil akhir.

  • Kode sumber untuk aplikasi React ini tersedia di Github dan ada aplikasi yang dihosting di vercel.

Kesimpulan

Fiuh! Ini adalah perjalanan yang panjang, jadi mari kita selesaikan. Saya mendorong Anda untuk melihat entri MDN untuk pekerja web (lihat daftar sumber daya di bawah) untuk mempelajari cara lain menggunakan pekerja web.

Dalam artikel ini, kami mempelajari tentang apa itu pekerja web dan jenis masalah yang harus mereka selesaikan. Kami juga melihat bagaimana menerapkannya menggunakan JavaScript biasa. Terakhir, kita melihat bagaimana mengimplementasikan pekerja web dalam aplikasi React.

Saya mendorong Anda untuk memanfaatkan API hebat ini untuk memberikan pengalaman yang lebih baik bagi pengguna Anda.

Sumber Daya Lebih Lanjut

  • Console.time() , dokumen web MDN
  • {JSON} Placeholder, situs web resmi
  • Menggunakan Pekerja Web, dokumen web MDN
  • Bilangan Fibonacci, Wikipedia
  • Operator bersyarat (ternary), dokumen web MDN
  • Document , API Web, dokumen web MDN
  • Memulai, Buat Aplikasi React (docs)
  • Function.prototype.toString() , dokumen web MDN
  • IIFE, dokumen web MDN
  • workerSetup.js , Tutorial Fullstack yang Luar Biasa, GitHub
  • “Pemrograman Paralel Dalam JavaScript Menggunakan Pekerja Web,” Uday Hiwarale, Medium