Chuyện gì đã xảy ra vậy?!
Một đề xuất cho tính năng ngôn ngữ JavaScript có tên là Array.prototype.flatten
hóa ra không tương thích với Web. Việc phát hành tính năng này trong Firefox Nightly đã khiến ít nhất một trang web phổ biến bị hỏng. Do mã có vấn đề là một phần của thư viện MooTools phổ biến, nên nhiều trang web khác có thể bị ảnh hưởng. (Mặc dù MooTools không thường được dùng cho các trang web mới trong năm 2018, nhưng trước đây nó từng rất phổ biến và vẫn xuất hiện trên nhiều trang web chính thức.)
Tác giả đề xuất đã đề xuất một cách đùa rằng nên đổi tên flatten
thành smoosh
để tránh vấn đề về khả năng tương thích. Không phải ai cũng hiểu được trò đùa này, một số người bắt đầu tin nhầm rằng tên mới đã được quyết định và mọi thứ nhanh chóng leo thang.
Array.prototype.flatten
có chức năng gì?
Array.prototype.flat
, ban đầu được đề xuất là Array.prototype.flatten
, làm phẳng các mảng theo đệ quy cho đến depth
được chỉ định, mặc định là 1
.
// Flatten one level:
const array = [1, [2, [3]]];
array.flat();
// → [1, 2, [3]]
// Flatten recursively until the array contains no more nested arrays:
array.flat(Infinity);
// → [1, 2, 3]
Đề xuất tương tự bao gồm Array.prototype.flatMap
, tương tự như Array.prototype.map
, ngoại trừ việc làm phẳng kết quả thành một mảng mới.
[2, 3, 4].flatMap((x) => [x, x * 2]);
// → [2, 4, 3, 6, 4, 8]
MooTools đang làm gì để gây ra vấn đề này?
MooTools xác định phiên bản Array.prototype.flatten
không chuẩn của riêng họ:
Array.prototype.flatten = /* non-standard implementation */;
Cách triển khai flatten
của MooTools khác với tiêu chuẩn đề xuất.
Tuy nhiên, đây không phải là vấn đề! Khi trình duyệt phân phối Array.prototype.flatten
gốc, MooTools sẽ ghi đè phương thức triển khai gốc. Điều này đảm bảo rằng mã dựa vào hành vi của MooTools hoạt động như dự kiến, bất kể flatten
gốc có sẵn hay không.
Cho đến giờ thì mọi thứ vẫn ổn!
Rất tiếc, sau đó có một sự cố khác xảy ra. MooTools sao chép tất cả các phương thức mảng tuỳ chỉnh sang Elements.prototype
(trong đó Elements
là một API dành riêng cho MooTools):
for (var key in Array.prototype) {
Elements.prototype[key] = Array.prototype[key];
}
for
-in
lặp lại các thuộc tính "có thể liệt kê", không bao gồm các phương thức gốc như Array.prototype.sort
, nhưng bao gồm các thuộc tính được chỉ định thường xuyên như Array.prototype.foo = whatever
. Tuy nhiên, điều quan trọng là nếu bạn ghi đè một thuộc tính không thể liệt kê, chẳng hạn như Array.prototype.sort = whatever
, thì thuộc tính đó vẫn không thể liệt kê.
Hiện tại, Array.prototype.flatten = mooToolsFlattenImplementation
tạo một thuộc tính flatten
có thể liệt kê, vì vậy, thuộc tính này sẽ được sao chép vào Elements
sau. Tuy nhiên, nếu trình duyệt phân phối phiên bản gốc của flatten
, thì phiên bản này sẽ không thể liệt kê và không được sao chép vào Elements
. Mọi mã dựa vào Elements.prototype.flatten
của MooTools hiện đều bị hỏng.
Mặc dù có vẻ như việc thay đổi Array.prototype.flatten
gốc thành có thể liệt kê sẽ khắc phục được vấn đề, nhưng điều này có thể gây ra nhiều vấn đề về khả năng tương thích hơn nữa. Mọi trang web dựa vào for
-in
để lặp lại một mảng (đây là một phương pháp không tốt nhưng vẫn xảy ra) sẽ đột nhiên nhận được một vòng lặp lặp lại bổ sung cho thuộc tính flatten
.
Vấn đề cơ bản lớn hơn ở đây là sửa đổi các đối tượng tích hợp. Việc mở rộng nguyên mẫu gốc hiện được coi là một phương pháp không tốt, vì không kết hợp tốt với các thư viện khác và mã của bên thứ ba. Đừng sửa đổi các đối tượng mà bạn không sở hữu!
Tại sao chúng ta không giữ nguyên tên hiện tại và phá vỡ Web?
Vào năm 1996, trước khi CSS trở nên phổ biến và từ lâu trước khi "HTML5" ra đời, trang web Space Jam đã ra mắt. Ngày nay, trang web này vẫn hoạt động như cách đây 22 năm.
Điều đó đã xảy ra như thế nào? Có ai duy trì trang web đó trong suốt những năm qua, cập nhật trang web đó mỗi khi nhà cung cấp trình duyệt phát hành một tính năng mới không?
Hóa ra, "đừng làm hỏng Web" là nguyên tắc thiết kế hàng đầu cho HTML, CSS, JavaScript và mọi tiêu chuẩn khác được sử dụng rộng rãi trên Web. Nếu việc phát hành một tính năng trình duyệt mới khiến các trang web hiện tại ngừng hoạt động, thì điều đó sẽ gây bất lợi cho mọi người:
- khách truy cập vào các trang web bị ảnh hưởng đột nhiên gặp phải trải nghiệm người dùng bị gián đoạn;
- chủ sở hữu trang web chuyển từ một trang web hoạt động hoàn hảo sang một trang web không hoạt động mà không thay đổi gì;
- nhà cung cấp trình duyệt cung cấp tính năng mới sẽ mất thị phần do người dùng chuyển đổi trình duyệt sau khi nhận thấy "tính năng này hoạt động trong trình duyệt X";
- sau khi biết vấn đề về khả năng tương thích, các nhà cung cấp trình duyệt khác sẽ từ chối phân phối trình duyệt đó. Thông số kỹ thuật của tính năng không khớp với thực tế (“chỉ là một tác phẩm hư cấu”), điều này không tốt cho quá trình chuẩn hoá.
Chắc chắn, khi nhìn lại, MooTools đã làm sai — nhưng việc phá vỡ web không phải là hình phạt dành cho họ mà là hình phạt dành cho người dùng. Những người dùng này không biết công cụ moo là gì. Ngoài ra, chúng ta có thể tìm một giải pháp khác và người dùng có thể tiếp tục sử dụng web. Bạn có thể dễ dàng đưa ra lựa chọn.
Điều đó có nghĩa là không bao giờ có thể xoá các API không tốt khỏi Nền tảng web?
Còn tùy. Trong một số ít trường hợp, các tính năng không tốt có thể bị xoá khỏi Web. Ngay cả việc chỉ tìm hiểu xem có thể xoá một tính năng hay không cũng là một nỗ lực rất khó khăn, đòi hỏi phải có dữ liệu đo từ xa rộng rãi để định lượng số lượng trang web sẽ thay đổi hành vi. Tuy nhiên, bạn có thể làm việc này khi tính năng không đủ an toàn, gây hại cho người dùng hoặc rất hiếm khi được sử dụng.
<applet>
, <keygen>
và showModalDialog()
đều là ví dụ về các API không tốt đã được xoá thành công khỏi Nền tảng web.
Tại sao chúng ta không sửa MooTools?
Bạn nên vá MooTools để không còn mở rộng các đối tượng tích hợp sẵn. Tuy nhiên, cách này không giải quyết được vấn đề hiện tại. Ngay cả khi MooTools phát hành một phiên bản đã vá, tất cả các trang web hiện có sử dụng phiên bản đó đều phải cập nhật để khắc phục vấn đề về khả năng tương thích.
Mọi người không thể chỉ cập nhật bản sao MooTools của họ sao?
Trong một thế giới hoàn hảo, MooTools sẽ phát hành một bản vá và mọi trang web sử dụng MooTools sẽ được cập nhật một cách kỳ diệu vào ngày hôm sau. Vấn đề đã được giải quyết, đúng không?!
Rất tiếc, điều này là không thực tế. Ngay cả khi có người nào đó xác định được toàn bộ trang web bị ảnh hưởng, tìm được thông tin liên hệ cho từng trang web, liên hệ thành công với tất cả chủ sở hữu trang web và thuyết phục họ cập nhật (có thể là tái cấu trúc toàn bộ cơ sở mã), thì tốt nhất là toàn bộ quá trình này sẽ mất nhiều năm.
Xin lưu ý rằng nhiều trang web trong số này đã cũ và có thể không được duy trì. Ngay cả khi trình bảo trì vẫn còn hoạt động, họ có thể không phải là một nhà phát triển web có kỹ năng cao như bạn. Chúng tôi không thể yêu cầu mọi người thay đổi trang web đã hoạt động 8 năm chỉ vì một vấn đề về khả năng tương thích với web.
Quy trình của TC39 hoạt động như thế nào?
TC39 là ủy ban chịu trách nhiệm phát triển ngôn ngữ JavaScript thông qua tiêu chuẩn ECMAScript.
#SmooshGate khiến một số người tin rằng “TC39 muốn đổi tên flatten
thành smoosh
”, nhưng đó chỉ là một trò đùa nội bộ chưa được truyền đạt rõ ràng ra bên ngoài.
Các quyết định quan trọng như đổi tên đề xuất không được đưa ra một cách dễ dàng, không do một người đưa ra và chắc chắn không được đưa ra chỉ dựa trên một nhận xét trên GitHub.
TC39 hoạt động theo quy trình phân đoạn rõ ràng cho các đề xuất tính năng.
Các đề xuất ECMAScript và mọi thay đổi lớn đối với các đề xuất đó (bao gồm cả việc đổi tên phương thức) được thảo luận trong các cuộc họp TC39 và cần được toàn bộ ủy ban phê duyệt trước khi trở thành chính thức. Trong trường hợp của Array.prototype.flatten
, đề xuất đã trải qua một số giai đoạn thoả thuận, cho đến Giai đoạn 3, cho biết tính năng này đã sẵn sàng được triển khai trong trình duyệt web. Thông thường, các vấn đề về thông số kỹ thuật khác sẽ xuất hiện trong quá trình triển khai. Trong trường hợp này, ý kiến phản hồi quan trọng nhất là sau khi cố gắng gửi tính năng: tính năng này, ở trạng thái hiện tại, sẽ làm hỏng Web. Những vấn đề khó dự đoán như vậy là một trong những lý do khiến quy trình TC39 không chỉ kết thúc sau khi trình duyệt phát hành một tính năng.
TC39 hoạt động dựa trên sự đồng thuận, tức là ủy ban phải đồng ý về mọi thay đổi mới. Ngay cả khi smoosh
là một đề xuất nghiêm túc, có vẻ như một thành viên trong ủy ban sẽ phản đối đề xuất này và ủng hộ một tên phổ biến hơn như compact
hoặc chain
.
Việc đổi tên từ flatten
thành smoosh
(ngay cả khi đó không phải là một trò đùa) chưa bao giờ được thảo luận tại cuộc họp TC39. Do đó, quan điểm chính thức của TC39 về chủ đề này hiện chưa được xác định. Không một cá nhân nào có thể thay mặt cho tất cả TC39 cho đến khi đạt được sự đồng thuận tại cuộc họp tiếp theo.
Các cuộc họp của TC39 thường có sự tham gia của những người có nền tảng rất đa dạng: một số người có nhiều năm kinh nghiệm thiết kế ngôn ngữ lập trình, một số người khác làm việc trên trình duyệt hoặc công cụ JavaScript, và ngày càng có nhiều người tham dự đại diện cho cộng đồng nhà phát triển JavaScript.
Cuối cùng, SmooshGate đã được giải quyết như thế nào?
Trong buổi họp TC39 tháng 5 năm 2018, #SmooshGate đã được giải quyết chính thức bằng cách đổi tên flatten
thành flat
.
Array.prototype.flat
và Array.prototype.flatMap
được phân phối trong V8 phiên bản 6.9 và Chrome 69.