Giới hạn của WebAssembly và tầm quan trọng của Tree-shaking
-
Dù nhận được nhiều sự quan tâm và kỳ vọng, WebAssembly chỉ đạt được thành công khá hạn chế trên web
- Có những trường hợp thành công như Photoshop, nhưng nhìn chung không có nhiều dự án tận dụng WebAssembly
- Đặc biệt, WebAssembly không phù hợp với các ứng dụng dùng DOM nhiều
- Sự khác biệt trong mô hình lập trình giữa JavaScript và WebAssembly là một trong những nguyên nhân chính
-
WebAssembly ngoài các ngôn ngữ như C hay Rust thì chưa thật sự thành công
- Các ngôn ngữ như C# có bất tiện là phải đi kèm cả runtime như garbage collector
- Tuy nhiên, các tính năng mới của WebAssembly hỗ trợ reference type và garbage collection sẽ sớm được đưa vào, nên tình hình được kỳ vọng sẽ cải thiện
Khả năng tối ưu mã của trình biên dịch là chìa khóa cho thành công của WebAssembly
-
Để WebAssembly thành công trên web, trình biên dịch phải tạo ra được mã nhỏ gọn và hiệu quả
- Điều quan trọng là phải giữ kích thước tệp ở mức nhỏ, chỉ vài kilobyte
- Nếu không làm được điều đó thì chỉ còn cách dựa vào sự cường điệu hoặc một tệp người dùng cụ thể
-
Trong thế giới JavaScript, việc tối ưu kích thước mã đang được thực hiện thông qua bundler và các công cụ tương tự
- Tree-shaking là kỹ thuật chỉ đưa vào chương trình những hàm và kiểu dữ liệu thực sự được sử dụng
-
Tree-shaking là một phép ẩn dụ không phù hợp xét về mặt làm vườn lẫn thuật toán, nhưng đây vẫn là thuật ngữ được dùng rộng rãi
Tình hình Tree-shaking ở các ngôn ngữ khác
-
Với các ngôn ngữ có runtime nặng như Go hay Python, Tree-shaking vẫn chưa được tối ưu tốt
- Ngay cả chương trình Go đơn giản nhất khi biên dịch sang WebAssembly cũng có kích thước hơn 2MB
- Pyodide của Python cũng cần tải xuống khoảng 20MB dữ liệu
-
Trong môi trường máy chủ, kích thước binary không phải là vấn đề quá lớn
- Vì vậy, cho những môi trường bị hạn chế như di động, các toolchain rút gọn như MicroPython, TinyGo cũng được phát triển riêng
-
Các implementation ngôn ngữ dành cho môi trường web khó tránh khỏi việc khác với bản gốc
- Bởi bản thân việc tương tác với DOM đã là một môi trường khá đặc thù
- Trong trường hợp của ClojureScript, các khác biệt so với Clojure được tài liệu hóa riêng
Bàn về thuật toán Tree-shaking
-
Trình biên dịch Hoot Scheme mà tác giả đang phát triển hiện tạo ra mã Wasm cỡ khoảng 70KB
- Việc chỉ giữ lại các định nghĩa hàm (procedure) tương đối dễ
- Nhưng vẫn có một số điểm khó như bên dưới
-
Trong mô hình đánh giá
letrec*, các binding vừa mang tính đệ quy vừa có thứ tự, khiến trình biên dịch khó phân tích- Với record type, các callback trong vtable khiến nhiều đoạn mã bị giữ lại
-
Khi dùng các hàm có tính đa hình cao như
display, rất nhiều mã liên quan sẽ bị kéo vào- Dùng các hàm cụ thể như
write-stringsẽ tốt hơn
- Dùng các hàm cụ thể như
-
Để Tree-shaking tối ưu, cần có flow analysis
- Nếu biết rằng đối số bitvector sẽ không được truyền vào
display, ta có thể loại bỏ phần mã liên quan
- Nếu biết rằng đối số bitvector sẽ không được truyền vào
-
Trong Python, việc này còn khó hơn do dynamic dispatch,
__getattr__và các tính năng động khác- Cấu trúc module của Python cũng là một yếu tố làm Tree-shaking trở nên phức tạp
Tóm tắt
- Nhờ hỗ trợ GC, WebAssembly giúp có thể lập trình DOM bằng các ngôn ngữ ngoài JavaScript
- Nhưng để làm cho kích thước đầu ra đủ nhỏ, cần đầu tư đáng kể vào toolchain của từng ngôn ngữ
- Cần phát triển các toolchain riêng có áp dụng thuật toán Tree-shaking và tối ưu hóa thư viện chuẩn
Ý kiến của GN⁺
-
Khi WebAssembly hỗ trợ GC, việc dùng nhiều ngôn ngữ khác nhau cho phát triển web đã trở nên khả thi hơn, nhưng có vẻ vẫn còn nhiều khó khăn nếu muốn mang nguyên trạng toolchain của các ngôn ngữ hiện có sang. Có lẽ cần phát triển các implementation ngôn ngữ và kỹ thuật tối ưu hóa chuyên biệt cho môi trường web.
-
Để Tree-shaking hoạt động tốt với các ngôn ngữ kiểu động, có lẽ phân tích tĩnh là điều bắt buộc. Nhưng với những ngôn ngữ như Python có quá nhiều tính năng động thì điều này sẽ không hề dễ. Biết đâu một hướng đi khác là tạo mới ngay từ đầu một ngôn ngữ thuận lợi hơn cho phân tích tĩnh.
-
Những dự án thử nghiệm như Hoot hay TinyGo có vẻ sẽ là tài liệu tham khảo tốt. Tuy nhiên, để áp dụng các dự án như vậy vào sản phẩm thực tế thì có lẽ vẫn còn hơi sớm. Có lẽ chỉ còn cách cải thiện dần từng bước.
-
Nếu dự án không quá nhạy cảm về hiệu năng và ưu tiên tốc độ phát triển, các lựa chọn như Pyodide có thể đáng để thử. Nhưng nếu là sản phẩm coi trọng trải nghiệm người dùng, thì ở thời điểm hiện tại JavaScript có lẽ vẫn là lựa chọn tốt nhất.
-
Cũng có thể cân nhắc việc đưa những tính năng như Tree-shaking vào chính WebAssembly. Nhưng vì yêu cầu của từng ngôn ngữ là khác nhau nên chắc điều đó sẽ không dễ. Mặt khác, nếu xuất hiện một ngôn ngữ hỗ trợ Tree-shaking rất tốt thì có khi viết luôn bằng ngôn ngữ đó lại có lợi hơn. Thật tò mò không biết sự phân chia vai trò giữa WebAssembly và ngôn ngữ lập trình rồi sẽ hình thành ra sao.
1 bình luận
Ý kiến trên Hacker News
Tóm lại như sau:
floatVecthay choHashMaptalc)rand,fxhash)mainvà chỉ đưa mã có thể tiếp cận được vào tệp nhị phân cuối cùng.