SmooshGate 常見問題

Mathias Bynens
Mathias Bynens

你說了平滑怎麼了?!

名為 Array.prototype.flatten 的 JavaScript 語言功能「提案」似乎與網路不相容。在 Firefox 夜間推送這項功能,會導致至少一個熱門網站無法正常運作。由於有問題的程式碼是廣泛的 MooTools 程式庫的一部分,很可能是許多網站都受到影響。(雖然 MooTools 在 2018 年並不常用於新網站,但這個工具過去並不常見,但仍有許多生產網站使用。

提案作者為了避免相容性問題,建議將 flatten 重新命名為 smoosh。大家都不知道該說笑話,他們也以為新名稱已有所判定,且相關演進速度很快。

Array.prototype.flatten」有哪些功能?

Array.prototype.flat (最初提議為 Array.prototype.flatten),將整併陣列遞迴直到指定的 depth 為止,預設為 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]

相同的提案包含 Array.prototype.flatMap,與 Array.prototype.map 類似,差別在於前者會將結果扁平化為新的陣列。

[2, 3, 4].flatMap((x) => [x, x * 2]);
// → [2, 4, 3, 6, 4, 8]

MooTools 是什麼造成的?

MooTools 會定義自己的非標準 Array.prototype.flatten 版本:

Array.prototype.flatten = /* non-standard implementation */;

MooTools 的 flatten 實作方式與提議的標準不同。不過,這並不是問題!當瀏覽器原生提供 Array.prototype.flatten 時,MooTools 會覆寫原生實作。如此一來,無論原生 flatten 是否可用,依賴 MooTools 行為的程式碼都能正常運作。目前為止還不錯!

很遺憾,發生了其他問題。MooTools 會將所有自訂陣列方法複製到 Elements.prototype (其中 Elements 是 MooTools 專用的 API):

for (var key in Array.prototype) {
  Elements.prototype[key] = Array.prototype[key];
}

for-in 會疊代「可列舉」屬性,其中不包括 Array.prototype.sort 等原生方法,但包含 Array.prototype.foo = whatever 這類定期指派的屬性。但重點是,如果覆寫非列舉的屬性 (例如 Array.prototype.sort = whatever),該屬性仍不可列舉。

目前 Array.prototype.flatten = mooToolsFlattenImplementation 會建立列舉的 flatten 屬性,因此稍後會複製到 Elements。但是,如果瀏覽器寄送原生版本的 flatten,就會成為無法列舉的,且不會複製到 Elements所有依賴 MooTools 的 Elements.prototype.flatten 程式碼現已損毀。

雖然將原生 Array.prototype.flatten 變更為可列舉狀態可以解決這個問題,但可能造成更多相容性問題。每個網站都會使用 for-in 進行陣列疊代 (雖然這種做法並非好做法,但發生這種情況),此時 flatten 屬性會突然發生額外的迴圈疊代。

更嚴重的基礎問題是修改內建物件。擴充原生原型的設計有時因為無法與其他程式庫和第三方程式碼妥善組合,因此目前普遍會接受這種做法。請勿修改不屬於您的物件!

為什麼不直接保留現有名稱,阻擋網路世界?

1996 年,在 CSS 逐漸廣泛發展,在「HTML5」發展之前,Space Jam 網站已正式上線。時至今日,網站的運作方式 與 22 年前相同

怎麼會發生這種事?多年來,是否有人持續維護該網站,並在每次瀏覽器廠商推出新功能時更新網站?

結果,「請勿破壞網路」是 HTML、CSS、JavaScript 和網路上廣泛使用的任何其他標準設計原則。發布新的瀏覽器功能會導致現有網站停止運作,對「所有人」來說並不安全:

  • 受影響網站訪客的訪客突然流失
  • 這些網站擁有者從運作正常的網站 轉變為不正常運作的網站
  • 由於使用者發現「可在 X 瀏覽器內運作」後 改用其他瀏覽器,導致這項新功能的市佔率下降
  • 解決相容性問題後,其他瀏覽器廠商就會拒絕傳送該問題。地圖項目規格與現實 (「沒有,只是虛構作品」) 不符,這不適用於標準化過程。

當然,以回顧方向的 MooTools 確實做到了錯誤的事,但破壞網路並不會因此懲罰,使用者也不會因此受到懲罰。這些使用者並不知道什麼是平滑的工具 或者,我們也可以尋找其他解決方案,但使用者可以繼續使用網路。選擇物品輕而易舉。

這是否表示不可能將不良 API 從網路平台移除?

視情況而定。在極少數情況下,錯誤功能可能會從網路上移除。即使只是判斷是否能移除某項功能仍是艱鉅的任務,更需要大量的遙測技術,才能量化多少網頁會有哪些行為改變。但是,如果這項功能非常不安全、對使用者造成傷害,或在極少使用的情況下,就可能發生這種情況。

<applet><keygen>showModalDialog() 都是從網路平台成功移除的不良 API 示例。

為什麼不直接修理 MooTools?

修補 MooTools,使其不再延伸內建物件是很好的做法。但無法立即解決問題。即使 MooTools 已發布修補版本,使用這項工具的現有網站也必須進行更新,才能解決相容性問題。

大家不能只更新 MooTools 的副本呢?

在理想的情況下,MooTools 會發布修補程式,而所有使用 MooTools 的網站隔天都會神奇地更新。問題解決,對吧?

不切實際。即便有人想找出所有受影響的網站、管理每位網站的聯絡資訊、成功聯絡所有網站擁有者,並說服所有網站擁有者執行更新 (可能意味著要重構整個程式碼集),整個程序仍可能需要花費數年的時間。

請注意,這些網站中有許多是舊的,可能未維護。 即使維護人員還在附近,可能還是有可能並非像你一樣熟練的網頁程式開發人員。基於網路相容性的問題,我們無法預期每個人都會 變更 8 歲兒童的網站。

資訊公開和同意聲明 (TC3) 程序如何運作?

TC39 是負責透過 ECMAScript 標準改善 JavaScript 語言的委員會。

#SmooshGate 造成一些人相信「TC39 想將 flatten 重新命名為 smoosh」,但那是一種笑話,無法對外溝通。 重新命名提案等重大決策並非由單一人負責,也絕對不會根據單一 GitHub 註解進行過夜。

TC39 以明確的測試流程執行功能提案。在 TC39 會議期間,我們會討論 ECMAScript 提案及其對其進行的任何重大變更 (包括方法重新命名),而且必須在全部委員會核准後才能正式成為正式成員。以 Array.prototype.flatten 為例,提案已經歷幾個協議階段,到第 3 階段為止,表明這項功能已可在網路瀏覽器中實作。在實作過程中,常會遇到其他規格問題。就目前的情況而言,在嘗試發布產品「之後」,最重要的意見回饋就是:功能 (處於目前狀態) 會破壞網路。這類難以預測的問題是瀏覽器推出功能時,資訊公開和同意聲明 (TC39) 程序不會因此結束的問題的一部分。

TC39 是以「共識」為基礎運作,因此委員會必須就任何新的變更達成共識。即使 smoosh 為很嚴重的建議,委員會成員很有可能會拒絕使用該名稱,並使用較常見的名稱,例如 compactchain

在 TC39 會議中,有些人從未在 TC39 會議中討論過將 flatten 重新命名為 smoosh 的重新命名 (即使原本沒有笑話也是如此)。因此,這個主題目前尚無資訊公開和同意聲明 (TC39) 的立場。在下一場會議達成共識之前,沒有人可以代表所有 TC39 人員發言。

背景知識豐富的參與者通常會參加 TC39 會議:有些人具備多年的程式設計語言設計經驗,有些使用瀏覽器或 JavaScript 引擎,也有越來越多的參與者代表 JavaScript 開發人員社群。

SmooshGate 終於解決了哪些問題?

2018 年 5 月 TC39 會議期間,#SmooshGate 已透過將 flatten 重新命名為 flat 來正式解析。

Array.prototype.flatArray.prototype.flatMap 分別在 V8 6.9 和 Chrome 69 中推出。