Часто задаваемые вопросы по SmooshGate

Что за фигня произошла?!

Предложение о функции языка JavaScript под названием Array.prototype.flatten оказалось несовместимым с Интернетом. Добавление этой функции в Firefox Nightly привело к поломке как минимум одного популярного веб-сайта . Учитывая, что проблемный код является частью широко распространенной библиотеки 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 */;

Реализация flatten MooTools отличается от предлагаемого стандарта. Однако проблема не в этом! Когда браузеры поставляют Array.prototype.flatten изначально, MooTools переопределяет встроенную реализацию. Это гарантирует, что код, основанный на поведении MooTools, работает должным образом независимо от того, доступен ли собственный flatten . Все идет нормально!

К сожалению, потом происходит нечто другое. MooTools копирует все свои методы пользовательского массива в Elements.prototype (где Elements — это API, специфичный для MooTools):

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 . Любой код, использующий Elements.prototype.flatten от MooTools, теперь не работает.

Хотя кажется, что изменение собственного Array.prototype.flatten на перечислимый решит проблему, это, скорее всего, вызовет еще больше проблем с совместимостью. Каждый веб-сайт, использующий for - in для перебора массива (что является плохой практикой, но такое случается), внезапно получает дополнительную итерацию цикла для свойства flatten .

Более серьезной проблемой здесь является изменение встроенных объектов. Расширение собственных прототипов в настоящее время считается плохой практикой, поскольку оно плохо сочетается с другими библиотеками и сторонним кодом. Не изменяйте объекты, которыми вы не владеете!

Почему бы нам просто не сохранить существующее название и не разрушить Сеть?

В 1996 году, до того, как CSS получил широкое распространение, и задолго до того, как HTML5 стал реальностью, появился веб-сайт Space Jam . Сегодня сайт по-прежнему работает так же, как и 22 года назад.

Как это произошло? Кто-то поддерживал этот веб-сайт все эти годы, обновляя его каждый раз, когда производители браузеров выпускали новую функцию?

Как оказалось, «не ломайте Интернет» — это принцип дизайна номер один для HTML, CSS, JavaScript и любого другого стандарта, широко используемого в Интернете. Если выпуск новой функции браузера приводит к тому, что существующие веб-сайты перестают работать, это плохо для всех :

  • посетители затронутых веб-сайтов внезапно теряют пользовательский опыт;
  • владельцы веб-сайтов превратили идеально работающий веб-сайт в нефункциональный, ничего не меняя;
  • производители браузеров, поставляющие новую функцию, теряют долю рынка из-за того, что пользователи переключают браузеры, заметив, что «она работает в браузере X»;
  • как только становится известно о проблеме совместимости, другие поставщики браузеров отказываются его поставлять. Спецификация функций не соответствует действительности ( «ничто, кроме художественного произведения» ), что плохо для процесса стандартизации.

Конечно, оглядываясь назад, MooTools поступили неправильно, но взлом Интернета наказывает не их, а пользователей. Эти пользователи не знают, что такое инструмент moo. Альтернативно, мы можем найти другое решение, и пользователи смогут продолжать пользоваться Интернетом. Выбор сделать легко.

Означает ли это, что плохие API никогда не смогут быть удалены из веб-платформы?

Это зависит. В редких случаях плохие функции можно удалить из Интернета . Даже просто выяснить, можно ли удалить функцию, — очень сложная задача, требующая обширной телеметрии, чтобы количественно определить, сколько веб-страниц будет изменено в своем поведении. Но когда функция достаточно небезопасна, вредна для пользователей или используется очень редко, это можно сделать.

<applet> , <keygen> и showModalDialog() — это примеры плохих API, которые были успешно удалены из веб-платформы.

Почему бы нам просто не исправить MooTools?

Хорошей идеей является исправление MooTools, чтобы оно больше не расширяло встроенные объекты. Однако это не решает существующую проблему. Даже если MooTools выпустит исправленную версию, всем существующим веб-сайтам, использующим ее, придется обновиться, чтобы проблема совместимости исчезла.

Разве люди не могут просто обновить свою копию MooTools?

В идеальном мире MooTools выпустила бы патч, и каждый веб-сайт, использующий MooTools, волшебным образом обновился бы на следующий день. Проблема решена, да?!

К сожалению, это нереально. Даже если кто-то каким-то образом идентифицирует полный набор затронутых веб-сайтов, сможет найти контактную информацию для каждого из них, успешно связаться со всеми владельцами веб-сайтов и убедить их всех выполнить обновление (что может означать рефакторинг их всю базу кода), весь процесс в лучшем случае займет годы.

Имейте в виду, что многие из этих веб-сайтов устарели и, вероятно, не поддерживаются. Даже если сопровождающий все еще здесь, возможно, он не такой высококвалифицированный веб-разработчик, как вы. Мы не можем ожидать, что все пойдут и изменят свой восьмилетний веб-сайт из-за проблем с веб-совместимостью.

Как работает процесс TC39?

TC39 — это комитет, отвечающий за развитие языка JavaScript посредством стандарта ECMAScript.

#SmooshGate заставил некоторых поверить, что «TC39 хочет переименовать flatten в smoosh », но это была шутка, которая не была хорошо передана извне. Важные решения, такие как переименование предложения, не принимаются легкомысленно, не принимаются одним человеком и определенно не принимаются в одночасье на основе одного комментария GitHub.

TC39 использует четкий процесс подготовки предложений по функциям. Предложения ECMAScript и любые существенные изменения к ним (включая переименование методов) обсуждаются на заседаниях TC39 и должны быть одобрены всем комитетом, прежде чем они станут официальными. В случае с Array.prototype.flatten предложение уже прошло несколько этапов согласования, вплоть до этапа 3, что указывает на то, что функция готова к реализации в веб-браузерах. Во время реализации часто возникают дополнительные проблемы со спецификациями. В данном случае самая важная обратная связь пришла после попытки ее реализации: эта функция в ее текущем состоянии ломает Интернет. Подобные труднопредсказуемые проблемы являются одной из причин, почему процесс TC39 не заканчивается сразу после того, как браузеры реализуют новую функцию.

TC39 действует на основе консенсуса, то есть комитет должен согласовывать любые новые изменения. Даже если smoosh было бы серьезным предложением, вполне вероятно, что член комитета возражал бы против него в пользу более распространенного имени, такого как compact или chain .

Переименование с flatten на smoosh (даже если это не была шутка) никогда не обсуждалось на заседании ТК39. Таким образом, официальная позиция TC39 по этой теме в настоящее время неизвестна. Ни один человек не может выступать от имени всего TC39 до тех пор, пока на следующем заседании не будет достигнут консенсус.

На собраниях TC39 обычно присутствуют люди с самым разным опытом: некоторые имеют многолетний опыт проектирования языков программирования, другие работают над браузером или движком JavaScript, и все большее число участников присутствует, чтобы представлять сообщество разработчиков JavaScript.

Как в конечном итоге была решена проблема со SmooshGate?

Во время заседания TC39 в мае 2018 года проблема #SmooshGate была официально решена путем переименования flatten в flat .

Array.prototype.flat и Array.prototype.flatMap поставляются в версиях V8 v6.9 и Chrome 69.