Hello mọi người lại là Slao đây !
Như mọi người đã biết Javascript là một ngôn ngữ đơn luồng nên các tác vụ không thể chạy song song và khi dự án bắt đầu lớn nhất, có rất nhiều tác vụ thì nếu không có những cách, kỹ thuật xử lí bất đồng bộ như setTimeout, setInterval hay XMLHttpRequest, event trigger thì bạn không còn cách nào khác ngoài chờ đợi.
Không những thế với những tác vụ nặng về dữ liệu, logic nếu không xử lí đúng cách thì bạn có thể làm ứng dụng của bạn bị treo
Do đó nên là một cách để xử lí đa luồng (multi-threading task) khá tốt đó chính là Web Worker
-
Web Worker là gì
Web Worker là một đối tượng trong Javascript được tạo ra bởi các hàm contructor như
Worker
,SharedWorker
... với tham số được truyền vào là một file JS chứa các đoạn code sẽ được thực thi bởi Worker. Các script được viết trong file này sẽ được thực thi ngầm, nhưng không làm gián đoạn bất cứ thao tác nào trên UI cũng như các script khác ảnh hưởng đến trải nghiệm người dùng. Vì vậy với các tác vụ tốn nhiều thời gian các bạn có thể dùng Worker để xử lý.
Đây là một kiến trúc hoạt động cơ bản của Worker với 2 luồng chính đó là main thread (main.js) và worker(worker.js). Nhìn trong ảnh chúng ta có thể hình dung được cơ chế hoạt động qua lại giữa hai luồng là đều có thể trao đổi thông tin với nhau.
Ví dụ việc gọi API ban đầu tốn nhiều thời gian main thread có thể chuyển xuống cho worker xử lý, sau khi xử lý xong thì chuyển lại dữ liệu cho main.js.
Cả main thread và worker đều giao tiếp vào gửi dữ liệu cho nhau thông qua hàm postMessage(), và sử dụng hàm onmessage() để lắng nghe dữ liệu được gửi tới. Dữ liệu được gửi qua lại giữa hai tiến trình này là một bản sao chép.
Dưới đây là các ví dụ
- Ví dụ Web worker với Dedicated workers
Dedicated worker (worker dành riêng), đúng như tên gọi của nó, là worker chỉ có tương tác bởi script đầu tiên đã sinh ra nó. Trong phần này, chúng ta sẽ tập trung tìm hiển về dedicated worker (tất nhiên là chỉ ở mức cơ bản).
Đầu tiên kiểm tra xem trình duyệt có hỗ trợ hay không (thường hiện này đều hỗ trợ)
sau đó khỏi tạo Worker
file worker.js
file testWorker.tsx
Kết quả
Như mọi người thấy hàm tính toán số đã được chạy ngầm ở bên worker, javascript không cần phải đợi để có thể log kết quả ra
Nếu muốn ngừng ngay lập tức một worker đang chạy từ thread chính, chúng ta có thể sử dụng phương thức sau:
Thread của worker sẽ ngay lập tức bị kill mà không cần đợi các tác vụ của nó được thực thi xong.
Bên trong worker, nó cũng có thể tự kill mình bằng phương thức sau:
- Import các script khác
Worker có thể sử dụng importScript
để import các script khác. Nó có thể không có tham số (không import gì) hoặc các URI là các script cần import. Tất cả các importScript
sau đều hợp lệ:
`importScripts(); /* không import gì */
importScripts('foo.js'); /* imports 1 script "foo.js" */
importScripts('foo.js', 'bar.js'); /* imports 2 scripts */
importScripts('//example.com/hello.js'); /* You can import scripts từ bên ngoài */`
Trình duyệt sẽ load các script trong tham số và thực thi chúng. Tất cả các biến, hàm, v.v... của các script đó đều có thể truy cập được từ worker. Nếu script không thể load được, thì một exception là NETWORK_ERROR
sẽ được bắn ra, và các code tiếp theo nó sẽ bị dừng lại.
Việc load các script được import này sẽ được thực hiện lần lượt, và thực hiện đồng bộ. Nghĩa là các script được load trước sẽ được thực thi trước, sau đó mới load tiếp các script khác. Nhờ vậy, các hàm, biến được định nghĩa ở script trước có thể được truy cập ở script sau.
Lưu ý rằng, việc download các file từ URI có thể được thực hiện song song, nhưng việc thực thi code từ các file script đó chắc chắn sẽ là tuần tự. Hàm importScript
sẽ chỉ return (tức là đã thực thi xong) nếu các script trong tham số của nó được thực thi xong.
- Ví dụ với Shared Workers
Khác với Dedicated Worker thì Shared Worker có thể được truy cập từ nhiều đoạn script nào đó miễn là trong cùng một domain hay là cùng protocol, port, host.
### **Khởi tạo một Shared Worker**
Tạo một Shared Worker
cũng đơn giản như tạo một Worker
bình thường chỉ khác là chúng ta sẽ sử dụng Shared Worker object
thay vì Worker object
### **Tương tác với một Shared Worker**
Bất cứ một file script nào trong cùng một domain đều có thể gọi tới Shared Worker thông qua MessagePort object được tạo bởi thuộc tính port
thuộc SharedWorker interface
.
Việc gửi và nhận message từ các file script khác tới Shared Worker
phức tạp hơn một chút khi chúng cần thông qua object port
.
Để lắng nghe được message được gửi đến từ main thread
thì ở file shared worker
cần phải sử dụng onconnect handler
để kết nối với port
. Các ports được kết nói với worker
được truy cập thông qua thuộc tính ports
.
onconnect
sẽ được kích hoạt khi kết nối được mở giữa Shared Worker
và main thread
qua MessagePort
object. Sau đó các công việc khác như lắng nghe và gửi message trở lại cho main thread cũng giống như cách chúng ta làm với Dedicated Worker
.
Nếu sử dụng addEventListener
để lắng nghe message
event thì cần phải thêm port.start()
ở cuối bên trong onconnect
event.
- Kết luận
Worker thực sự là một giải pháp cho phép chúng ta thực hiện multithread với JavaScript rất hay
Dưới đây là một số tình huống chúng ta có thể sử dụng web worker trong ứng dụng web của mình:
- Tải trước dữ liệu nhưng không dùng ngay mà để sau này mới dùng đến.
- Các thao tác định dang văn bản real-time (ví dụ code highlight hay preview với các editor trên nền web).
- Kiểm tra chính tả, kiểm tra ngữ pháp của văn bản nhập vào.
- Xử lý, phân tích dữ liệu hình ảnh, âm thanh.
- Các thao tác truyền, nhận dữ liệu qua long polling.
- Xử lý một khối lượng dữ liệu JSON rất lớn.
Top comments (0)