- Kể từ lần ra mắt đầu tiên vào năm 2017, WebAssembly đã phát triển với khả năng hỗ trợ thực thi các ngôn ngữ mức thấp như C/C++, nhưng trên nền tảng web, nó vẫn bị đối xử như ngôn ngữ hạng hai
- Chỉ JavaScript mới có thể tương tác trực tiếp với Web API, còn WebAssembly phải viết mã binding JS phức tạp (glue code) để làm điều đó
- Cấu trúc này dẫn đến quy trình tải phức tạp, chi phí hiệu năng bổ sung, đứt gãy toolchain theo từng ngôn ngữ, làm suy giảm trải nghiệm lập trình viên
- Để giải quyết vấn đề này, Mozilla đề xuất WebAssembly Component Model, cho phép gọi Web API và tải mô-đun theo cách chuẩn hóa mà không cần JS
- Nếu mô hình này được thiết lập rộng rãi, WebAssembly được kỳ vọng sẽ trở thành môi trường thực thi hạng nhất trong trình duyệt, tạo nền tảng để cả các lập trình viên phổ thông cũng có thể dễ dàng sử dụng
Vì sao WebAssembly bị xem là ngôn ngữ hạng hai
- WebAssembly chỉ có thể truy cập nền tảng web thông qua JavaScript và không có quyền gọi Web API trực tiếp
- JavaScript có thể được tải đơn giản bằng thẻ
<script>, nhưng WebAssembly cần quy trình tải thủ công qua JS API
- Phải đi qua các lệnh gọi API phức tạp như
WebAssembly.instantiateStreaming(), và lập trình viên либо phải ghi nhớ chúng hoặc tự động hóa bằng công cụ
- Đề xuất esm-integration đơn giản hóa quy trình tải bằng cách cho phép import trực tiếp tệp
.wasm qua hệ thống mô-đun JS
- Có thể tải trực tiếp dưới dạng
<script type="module" src="/module.wasm"></script>
Hạn chế trong việc truy cập Web API
- Một việc trong JavaScript chỉ cần một dòng
console.log("hello, world") thì trong WebAssembly lại đòi hỏi truy cập bộ nhớ JS, giải mã chuỗi, bọc hàm và nhiều bước phức tạp khác
- WebAssembly không thể truy cập đối tượng
console hay DOM, nên phải gọi gián tiếp từ JS thông qua chia sẻ bộ nhớ và import/export hàm
- Mã binding (glue code) sinh ra trong quá trình này khác nhau theo từng ngôn ngữ, và thường được tạo tự động bằng các công cụ như
embind, wasm-bindgen
- Tuy nhiên, điều này lại gây ra các vấn đề như tăng độ phức tạp khi build, overhead lúc chạy, và thiếu tương thích giữa các ngôn ngữ
Các nguyên nhân kỹ thuật khiến WebAssembly chưa thể trở thành ngôn ngữ hạng nhất
- Khó khăn trong tích hợp compiler: compiler của mỗi ngôn ngữ phải tự sinh mã tích hợp với JS và nền tảng web, và phần này không thể tái sử dụng
- Compiler chuẩn không tương thích: tệp được tạo bằng
rustc --target=wasm không thể chạy ngay trong trình duyệt
- Cần cài thêm toolchain không chính thức có triển khai tích hợp nền tảng
- Sự thiên lệch của hệ sinh thái tài liệu: tài liệu web như MDN phần lớn được viết xoay quanh JavaScript, khiến người dùng ngôn ngữ khác gặp rào cản gia nhập cao
- Vấn đề hiệu năng: các lệnh gọi DOM đi qua binding JS bị chậm hơn 45% so với gọi trực tiếp
- Trong thử nghiệm với framework Dodrio, khi bỏ JS glue thì thời gian áp dụng thay đổi DOM giảm còn một nửa
- Sự phụ thuộc vào JavaScript: để dùng WebAssembly trong thực tế, cuối cùng vẫn phải hiểu JS, dẫn đến vấn đề abstraction bị rò rỉ (leaky abstraction)
Sự xuất hiện của WebAssembly Component Model
- WebAssembly Component Model định nghĩa đơn vị thực thi chuẩn hóa có thể dùng chung giữa nhiều ngôn ngữ và runtime
- Có thể trực tiếp thực hiện việc truy cập Web API, tải mô-đun và liên kết mà không cần JS
- Có thể được tạo từ nhiều ngôn ngữ khác nhau và được hỗ trợ thực thi trên nhiều runtime như trình duyệt hay Wasmtime
- Thông qua WIT (Interface Description Language), có thể khai báo API cần dùng và gọi trực tiếp từ bên trong component
- Trình duyệt có thể tải component trực tiếp bằng
<script type="module" src="component.wasm"></script>, và tự động xử lý binding Web API mà không cần JS
Khả năng tương tác với JavaScript
- Component Model cũng hỗ trợ cấu trúc ứng dụng hybrid
- Ví dụ: viết bộ giải mã ảnh bằng WebAssembly, rồi gọi từ JS theo dạng
import { Image } from "image-lib.wasm";
- JS có thể dùng component WebAssembly như một mô-đun thông thường thông qua import/export
Triển vọng và cách tham gia
- Mozilla đang hợp tác với WebAssembly CG để chuẩn hóa Component Model, và Google cũng đang ở giai đoạn xem xét
- Lập trình viên có thể thử nghiệm trên trình duyệt hoặc CLI thông qua Jco hay Wasmtime
- Nếu mô hình này được phổ biến, WebAssembly có thể mở rộng từ “tính năng dành cho power user” thành công nghệ web mà cả lập trình viên phổ thông cũng có thể sử dụng
4 bình luận
Đây gần như chỉ là kiểu kỳ vọng mang màu sắc Mozilla mà thôi. Frontend về mặt cấu trúc không thể thoát khỏi hệ viền của phản ứng thị trường. Ngay khi WebAssembly xuất hiện thì Doom 3 đã được port sang rồi. DOM trong các trình duyệt hiện đại từ lâu đã chuyển thành các đối tượng proxy nhẹ, và nếu xét đến tập lệnh chuyên dụng cho JavaScript của CPU hiện đại cùng giới hạn lượng tử của lõi đơn, thì cách tiếp cận này sẽ không bao giờ giành được ưu thế về giá trị thị trường.
Một binary WebAssembly chạy bên trong Electron thì có ý nghĩa gì? Cái này chỉ giống thêm một cuộc săn danh tiếng kiểu GitKraken CLI hoặc port sang Rust mà thôi.
Không nói về những thứ khác, nhưng cách nhúng module wasm dưới dạng tệp như
<script type="module" src="/module.wasm"></script>thì khá hấp dẫn đấy.Và cũng phải nói cho rõ rằng những lập luận cho rằng WebAssembly có rào cản gia nhập cao là rất vô lý. Chỉ đơn giản là mức độ cần thiết của việc đó thấp hơn mức sẵn sàng chi trả mà thôi. Muốn vừa nhanh vừa có footprint thấp, nhưng vẫn muốn dùng DOM và CSS ư? Đây là kiểu hài đen gì vậy.
Ý kiến trên Hacker News
Thật đáng tiếc khi họ từ bỏ mục tiêu ban đầu là hỗ trợ WebIDL trong WebAssembly, rồi lại quyết định tạo ra một IDL khác, trong khi không coi việc thiếu truy cập DOM là vấn đề
Dĩ nhiên tôi hiểu thực tế thị trường, nhưng vẫn không thể xua đi cảm giác tiếc nuối vì thời gian đã mất
Tham khảo liên quan: lịch sử commit, hồi tưởng về stringref, bài viết trên ACM
Sau đó có thêm hai mục tiêu nữa: một là hỗ trợ API ngoài web, hai là khả năng tương tác giữa các ngôn ngữ
WebIDL là hợp của JS và Web API nên có sức biểu đạt cao, nhưng lại có nhiều khái niệm xung đột với các mục tiêu đó
Vì vậy component interface đã chọn cách tiếp cận là phần giao nhau có tính di động cao hơn nhiều, dù sức biểu đạt giảm đi
Cá nhân tôi nghĩ truy cập DOM là quan trọng, nhưng Wasm CG đã bận với những việc có ưu tiên cao hơn
Lý do tôi viết bài này là muốn cho mọi người biết rằng chúng tôi vẫn nhớ tới vấn đề này và dự định sẽ tiếp tục làm
Toolchain và quy trình build quá phức tạp, nên mỗi lần dùng tôi đều cảm thấy gánh nặng nhận thức
Hiệu năng tốt hơn nhiều khi không có glue, nhưng đồng thời rủi ro cũng lớn hơn tương ứng
Tôi hy vọng component model sẽ không đưa thêm độ phức tạp mới, nhưng nhìn các ví dụ đa ngôn ngữ thì có vẻ đã khá rối rồi
Đặc biệt khi xem ví dụ Go, có quá nhiều file được sinh ra, và từ góc độ lập trình viên thì việc đơn giản hóa tooling là cực kỳ cấp thiết
Hiện giờ trông không giống như đang loại bỏ độ phức tạp, mà chỉ là chuyển nó sang chỗ khác
Đặc tả wasm component liên tục thay đổi nên có rất nhiều churn
Mục tiêu là để lập trình viên web không phải tự viết WIT, mà có thể dùng Web API như một thư viện
Nhưng hiện tại vẫn còn rất nhiều việc phải làm
Ví dụ có thể chia thành chia sẻ văn bản, chia sẻ media, chia sẻ ứng dụng... như vậy bảo mật cũng tốt hơn và các nhóm nhỏ cũng có thể tạo ra lựa chọn thay thế cho trình duyệt
Nhưng quy mô khổng lồ của Web API và CSS là thứ đang nâng đỡ thế độc quyền của trình duyệt, nên có lẽ những thử nghiệm như vậy sẽ khó thành hiện thực
Sẽ rất tốt nếu có thể chuẩn hóa một WebAssembly registry để các component dễ dàng được ghép nối với nhau
Rốt cuộc web là quá trình tạo ra định nghĩa của một hệ điều hành phân tán
Từ khái niệm đến ví dụ mã đều được sắp xếp rất tốt
Trong hệ sinh thái JS, ba dự án cốt lõi là StarlingMonkey, ComponentizeJS, jco
Hiện tại toolchain trưởng thành nhất là Rust, nhưng hỗ trợ cho các ngôn ngữ dựa trên LLVM (C/C++, Go, Python...) cũng đang dần tốt lên
Mục tiêu của WebAssembly là trở thành một đích biên dịch hòa nhập tự nhiên vào toolchain cục bộ
Nếu vẫn phải hiểu glue code theo từng ngôn ngữ hay phải nắm hai mô hình runtime, thì WebAssembly vẫn sẽ chỉ là “một công cụ chỉ dùng trong tình huống cực đoan”
Muốn tạo ra thay đổi thật sự thì phải đơn giản hóa con đường build thông thường
Chưa rõ phần này được xử lý như thế nào trong Component Model
DOM khác nhau giữa các trình duyệt, và tính năng cũng thay đổi theo từng lần tải trang
Ở lớp JS bridge thì có thể dễ dàng áp dụng polyfill, nhưng với giao diện WIT thì việc phát hiện method lúc runtime hay polyfill lại rất khó
Ngoài hiệu năng, tính linh hoạt của hệ sinh thái cũng quan trọng
Việc phải tự quản lý glue code JS hoặc dựa vào công cụ sinh tự động khiến nó giống như một bước lùi lớn
Việc thí nghiệm Dodrio bỏ qua glue và đạt giảm 45% overhead là rất ấn tượng
Tuy vậy tôi vẫn tò mò việc quản lý bộ nhớ sẽ diễn ra thế nào khi WebAssembly Component Model tương tác trực tiếp với Web API
Tôi muốn biết liệu đề xuất Wasm GC có được dùng để giữ tham chiếu DOM hay vẫn còn phụ thuộc vào JS GC
Tôi mong Wasm thật sự trở thành một công dân hạng nhất
Nhưng hiện tại IPC vẫn còn kém hiệu quả, và tôi nghĩ cần những cách như truyền theo đơn vị trang bộ nhớ
Việc cho phép bất kỳ ai chạy những chương trình phức tạp trên máy tính của tôi là một ý tưởng điên rồ về mặt bảo mật, nhưng thực tế chúng ta đã làm vậy
Nhờ JS mà trong 20 năm qua chúng ta đã trải qua vô số lỗi bảo mật trình duyệt, nhưng giờ đây các nguyên tắc thiết kế và biện pháp giảm thiểu đã được định hình
Thế mà giờ lại định thay nó bằng một mô hình thực thi nguy hiểm khác, điều đó vừa mỉa mai vừa đẹp theo cách nào đó
OS di động làm điều đó tốt hơn desktop rất nhiều
Chúng được thiết kế thiên về góc nhìn kỹ sư, và không có workflow mặc định thân thiện với người viết ứng dụng
Dù vậy vẫn đáng mừng khi còn có những người quan tâm đến các vấn đề này
Nó giống như đang làm quá nhiều kỹ thuật chỉ để có xử lý chuỗi nhanh gấp đôi nhằm ánh xạ DOM API theo kiểu 1:1
Với các API như WebGL2, WebGPU, WebAudio thì chi phí của JS shim vốn đã rất nhỏ
Vấn đề thực sự là những chỗ như sao chép buffer GPU, mà component model không giúp được gì ở đó
Tôi muốn xem benchmark thử nghiệm hàng chục nghìn draw call trên WebGL2 hay WebGPU
Ngoài hiệu năng ra, việc cải thiện trải nghiệm lập trình viên (DX) cũng rất quan trọng
Hiện giờ việc bắt đầu quá khó, và ai cũng phải trở thành chuyên gia thì mới tận dụng được lợi ích
Nếu có thể cạnh tranh với hiệu quả ở mức ứng dụng native, đây sẽ là một thay đổi có tầm nhìn cho tương lai của web
Trong thời đại coding agent, những cải thiện DX mà họ nói tới không còn quan trọng nữa