Câu hỏi thường gặp về SmooshGate

Chuyện gì xảy ra với tính năng smoosh?!

Đề xuất cho một tính năng ngôn ngữ JavaScript có tên là Array.prototype.flatten hoá ra không tương thích với web. Việc vận chuyển tính năng này trong Firefox Nightly đã khiến ít nhất một trang web phổ biến gặp sự cố. Vì mã có sự cố là một phần của thư viện MooTools phổ biến nên có khả năng nhiều trang web khác cũng bị ảnh hưởng. (Mặc dù MooTools không thường được sử dụng cho các trang web mới trong năm 2018, nhưng MooTools từng rất phổ biến và vẫn xuất hiện trên nhiều trang web sản xuất.)

Người viết đề xuất nói đùa là nên đổi tên flatten thành smoosh để tránh vấn đề về khả năng tương thích. Mọi người không hiểu rõ chuyện cười này. Một số người bắt đầu hiểu 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 dưới dạng Array.prototype.flatten, làm phẳng các mảng theo quy tắc đệ quy lên đế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]

Cùng một đề xuất bao gồm Array.prototype.flatMap, tương tự như Array.prototype.map, ngoại trừ việc nó 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ì mà gây ra sự cố này?

MooTools xác định phiên bản Array.prototype.flatten không chuẩn của riêng chúng:

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 gửi Array.prototype.flatten theo nguyên 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 sẽ hoạt động như dự kiến, bất kể có flatten gốc hay không. Đến giờ thì mọi thứ vẫn ổn!

Thật không may, có điều gì đó khác sẽ xảy ra. MooTools sẽ sao chép tất cả các phương thức mảng tuỳ chỉnh vào 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 "liệt kê", không bao gồm các phương thức gốc như Array.prototype.sort, nhưng có bao gồm các thuộc tính được chỉ định thường xuyên như Array.prototype.foo = whatever. Tuy nhiên, đây là phần giới thiệu. Nếu bạn ghi đè một thuộc tính không thể liệt kê, ví dụ: Array.prototype.sort = whatever, bạn vẫn không thể liệt kê được.

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, sau đó thuộc tính này sẽ được sao chép vào Elements. Tuy nhiên, nếu các trình duyệt gửi phiên bản gốc của flatten, thì phiên bản đó sẽ không liệt kê được và không được sao chép vào Elements. Mọi mã dựa vào Elements.prototype.flatten của MooTools nay đã bị lỗi.

Mặc dù có vẻ như việc thay đổi Array.prototype.flatten gốc thành liệt kê sẽ khắc phục được vấn đề, nhưng điều này có thể còn 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à phương pháp không tốt nhưng vẫn xảy ra) thì sẽ đột nhiên nhận được một vòng lặp bổ sung cho thuộc tính flatten.

Vấn đề lớn hơn cơ bản ở đây là việc sửa đổi các đối tượng tích hợp sẵn. Hiện nay, việc mở rộng nguyên mẫu gốc thường được chấp nhận là một phương pháp không phù hợp, vì nó không kết hợp hiệu quả với các thư viện và mã bên thứ ba khác. Đừng sửa đổi các đối tượng mà bạn không sở hữu!

Vì sao chúng tôi không giữ nguyên tên hiện có và truy cập trang web?

Vào năm 1996, trước khi CSS trở nên phổ biến và rất lâu trước khi "HTML5" trở thành một thứ, trang web Space Jam đã ra mắt. Ngày nay, trang web vẫn hoạt động giống như 22 năm trước.

Việc này 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 các nhà cung cấp trình duyệt chuyển một tính năng mới không?

Hoá ra, “đừng phá vỡ web” là nguyên tắc thiết kế số một cho HTML, CSS, JavaScript và bất kỳ tiêu chuẩn nào khác được sử dụng rộng rãi trên Web. Nếu việc chuyển một tính năng của trình duyệt mới khiến các trang web hiện có ngừng hoạt động thì điều đó sẽ có ảnh hưởng xấu đến mọi người:

  • khách truy cập trang web bị ảnh hưởng đột nhiên có trải nghiệm người dùng bị hỏng;
  • chủ sở hữu trang web chuyển từ có một trang web hoạt động hoàn hảo thành một trang web không hoạt động mà không cần phải thay đổi bất cứ điều gì;
  • các nhà cung cấp trình duyệt vận chuyển tính năng mới này bị 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";
  • 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 gửi bản ghi đó. Thông số kỹ thuật của tính năng không phù hợp với thực tế (“không có gì khác ngoài tác phẩm hư cấu”), điều này không tốt cho quá trình tiêu chuẩn hoá.

Chắc chắn rồi, khi nhìn lại thì MooTools đã làm điều sai trái, nhưng việc phá vỡ web không khiến họ bị phạt mà còn khiến người dùng bị trừng phạt. Những người dùng này không biết công cụ moo là gì. Ngoài ra, chúng tôi 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. Lựa chọn này rất dễ thực hiện.

Có phải điều đó có nghĩa là tuyệt đối không thể xoá các API không hợp lệ khỏi Nền tảng web không?

Còn tùy. Trong một số ít trường hợp, các tính năng không hợp lệ có thể bị xoá khỏi Web. Ngay cả chỉ tìm hiểu xem có thể xoá một tính năng hay không cũng là một công việc rất khó khăn, việc yêu cầu phương pháp đo lường từ xa rộng rãi để định lượng xem có bao nhiêu trang web sẽ thay đổi hành vi của chúng. Tuy nhiên, khi tính năng này không đủ an toàn, có hại cho người dùng hoặc hiếm khi được sử dụng, thì điều này có thể được thực hiện.

<applet>, <keygen>showModalDialog() đều là ví dụ về các API không hợp lệ đã bị 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 nữa. Tuy nhiên, nó không giải quyết được vấn đề hiện tại. Ngay cả khi MooTools sắp phát hành một phiên bản đã vá, thì tất cả trang web hiện đang sử dụng phiên bản này vẫn phải cập nhật để loại bỏ vấn đề về khả năng tương thích.

Mọi người có thể chỉ cập nhật bản sao MooTools của họ không?

Trong một thế giới hoàn hảo, MooTools sẽ phát hành bản vá và mọi trang web sử dụng MooTools sẽ kỳ diệu được cập nhật vào ngày tiếp theo. Vấn đề đã được giải quyết rồi đúng không?!

Rất tiếc là điều này không thực tế. Ngay cả khi ai đó bằng cách nào đó xác định được toàn bộ trang web bị ảnh hưởng, hãy quản lý để tìm thông tin liên hệ của 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 tất cả thực hiện cập nhật (tức 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 người bảo trì vẫn còn hiện diện, có thể họ không phải là nhà phát triển web có kỹ năng cao như bạn. Chúng tôi không thể mong đợi mọi người đều đi thay đổi trang web đã 8 năm tuổi của họ do vấn đề về khả năng tương thích với web.

Quy trình TC39 hoạt động như thế nào?

TC39 là uỷ 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 đây là một trò đùa mà không được truyền đạt rõ ràng đến bên ngoài. Những quyết định quan trọng như đổi tên đề xuất không được cân nhắc, không phải do một người duy nhất đưa ra và chắc chắn là không được đưa ra qua đêm dựa trên một nhận xét duy nhất của GitHub.

TC39 hoạt động trên quy trình thử nghiệm rõ ràng đối với các đề xuất về tính năng. Các đề xuất của ECMAScript và mọi thay đổi chính đố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 phải được toàn bộ uỷ ban phê duyệt trước khi chính thức trở thành chính thức. Trong trường hợp 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 để triển khai trong các trình duyệt web. Thông thường, các vấn đề về thông số kỹ thuật bổ sung 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 đến sau khi cố gắng gửi đi: tính năng ở trạng thái hiện tại sẽ gây lỗi cho môi trường Web. Các vấn đề khó dự đoán như thế này là một phần lý do khiến quy trình TC39 không chỉ kết thúc sau khi các trình duyệt gửi một tính năng.

TC39 hoạt động dựa trên sự đồng thuận, có nghĩa là uỷ ban phải thống nhất 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 uỷ ban sẽ phản đối đề xuất này và thay bằng 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 từng được thảo luận tại cuộc họp TC39. Do đó, hiện chưa có quan điểm chính thức của TC39 về chủ đề này. Không một cá nhân nào có thể phát biểu thay mặt cho toàn bộ 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 TC39 thường tham dự bởi những người có nền tảng kiến thức cực kỳ đ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, số khác làm việc trên trình duyệt hoặc công cụ JavaScript, và số lượng người tham dự ngày càng tăng lên để đại diện cho cộng đồng nhà phát triển JavaScript.

Rốt cuộc thì SmooshGate đã được giải quyết như thế nào?

Trong cuộc họp TC39 tháng 5 năm 2018, #SmooshGate đã chính thức được giải quyết bằng cách đổi tên flatten thành flat.

Array.prototype.flatArray.prototype.flatMap được phát hành trong phiên bản 8.9 và Chrome 69.