Pull to refresh

О том, как ошибка, найденная в IE9 Platform Preview, стала причиной изменения стандарта Javascript

Reading time5 min
Views1K
Original author: Allen Wirfs-Brock
image
Когда мы впервые обнародовали наши планы по поводу предварительных версий IE9, мы сказали что «разработчики и люди, интересующиеся стандартами и веб-разработкой, смогут попробовать предварительную версию IE9 и высказать свои замечания и предложения относительно его работы». На данный момент мы ежедневно получаем отзывы и используем их для улучшения Internet Explorer 9. Однако обратная связь иногда касается не только IE9. Эта история о том, как недавний отзыв на Internet Explorer 9 Platform Preview вызвал изменение нового стандарта JavaScript – 5-ую редакцию EcmaScript.

Стандарт «EcmaScript 5» был официально принят в декабре 2009 года, и третья предварительная версия Internet Explorer 9 является нашей первой наиболее полной его реализацией. ES5 был спроектирован так, чтобы оставаться полностью совместимым с существующими сайтами, и технический комитет TC39 работал над тем, чтобы избежать любых не связанных с безопасностью изменений, которые могли бы привести в нерабочее состояние существующий JavaScript-код. Однако в мире программного обеспечения ничего совершенного не бывает, и, когда мы выпустили третью предварительную версию Internet Explorer 9, нам стало интересно, обнаружатся ли какие-нибудь проблемы совместимости с существующими сайтами, связанные с ES5.

image
Вскоре после выпуска предварительной версии нашего браузера мы получили несколько жалоб, что некоторые веб-приложения, использующие jQuery некорректно работают в IE9. Мы выяснили, что проблема заключалась в следующем методе JQuery API, который в некоторых случаях не работал, потому что код метода перед вызовом Object.prototype.toString не проверял переданное пользователем значение на null или undefined. В частности некоторые вызовы этого метода jQuery
isFunction: function( obj ) {
   return toString.call(obj) === "[object Function]";
}


* This source code was highlighted with Source Code Highlighter.

завершаются исключением: “TypeError: Object expected”. Дальнейший анализ показал, что toString является встроенным методом Object.prototype.toString, который вызывал сбой, когда isFunction вызывала его со значением undefined в качестве аргумента. Почему данное исключение возникало только в IE9, а не в более ранних версиях IE, а также в браузерах других производителей? Именно потому, что поведение третей предварительной версии IE9 в режиме стандартов действительно соответствует спецификации ES5 Object.prototype.toString.

Согласно предыдущей спецификации EcmaScript вызов встроенного метода с параметром null или undefined приводит к передаче «глобального объекта» (у браузеров это объект DOM window). Это открывает целый ряд потенциальных дыр в безопасности для фреймворков, цель которых обеспечить работу веб-приложений в безопасном режиме.

Спецификация ES5 изменила данное поведение так, что передача null или undefined не приводит к передаче в функцию объекта window. Определение каждого встроенного метода было обновлено специально для решения проблемы получения этих значений в качестве значения this. Технический комитет пытался сделать так, чтобы сохранить обратную совместимость для обычного использования и генерировать исключение в случае, когда это невозможно. Это создало проблему совместимости, описанную выше.

Данная проблема может быть просто решена изменением кода jQuery:
isFunction: function( obj ) {
   return obj && toString.call(obj) === "[object Function]";
},


* This source code was highlighted with Source Code Highlighter.

На самом деле команда jQuery планирует внести данное изменение. Однако данное изменение не затронет тысячи локально используемых библиотек jQuery существующих в вебе. Учитывая широкую распространенность jQuery, становится очевидным, что спецификация ES5 содержит серьезную проблему совместимости. Также вполне очевидно, каким образом мы можем изменить нашу реализацию ES5 в IE9 для решения проблемы. Мы можем просто вернуть строковое значение "[object Object]", это же значение возвращает IE8 в данной ситуации. Такой фикс не добавляет проблем с безопасностью, которые старается решить ES5. Тем не менее, мы не хотим в одностороннем порядке вводить такое различие в нашу реализацию нового стандарта. Данное решение не поможет решению проблем совместимости и интероперабельности, если IE исправит эту проблему одним из способов, а другие браузеры не исправят вообще или сделают это иначе.

Как только мы разобрались в проблеме и возможном решении, я поднял этот вопрос в списке рассылки для обсуждений комитета TC39. Мое первое сообщение по данной проблеме было опубликовано в 17:51 в пятницу 25 июня. К 22 часам уже были получены ответы от членов TC39, представляющих Apple, Mozilla и Google. Мы все согласились, что это была проблема совместимости, которую необходимо решить, и генерация исключения в данном случае не нужна и нежелательна. Изначально мы согласились с тем, что идея возврата строкового значения, как написано в ES3, для таких случаев выглядит как хорошая идея. Тем не менее, при дальнейшем обсуждении на выходных мы поняли, что не все браузеры в данный момент возвращают "[object Object]", мы также рассматривали следующие значения "[object Window]" и "[object Global]".

Было предложено возвращать "[object null]" и "[object undefined]". Это решение, кажется, лучшее, поскольку не только устраняет такую проблему, как в случае jQuery, но и позволяет явно различать неопределенные и null-объекты. Данное решение также повышает интероперабельность браузеров, потому что требует, чтобы браузеры выдавали одинаковый результат, а не ситуацию ES3, которая приводила к различным результатам в различных браузерах.

Во вторник данное решение было принято консенсусом как окончательное. Как только было достигнуто согласие, я передал пересмотренные спецификации Object.prototype.toString в команду разработчиков IE9 JavaScript, чтобы они могли внести исправления в текущую реализацию перед публичным испытанием следующей предварительной версии IE9. Mozillа также подтвердила, что примет данное исправление в следующей бета-версии Firefox. Я также обновил официальный список исправлений TC39 для ES5, это изменение описано в разделе 15.2.4.2 спецификации.

Веб-стандарты – сложные программные артефакты, и как все ПО, они содержат ошибки. Иногда лучший способ найти и исправить ошибку совместимости, это реализовать стандарт в широко распространенном браузере. Данный способ обычно применяется в контексте выпуска ранних версий браузера, как в случае с Internet Explorer 9 Platform Preview. Таким образом, когда вы, как веб-разработчик отправляете фидбек на какой-либо конкретный браузер, вы также даете обратную связь тем стандартам, которые он реализует. Конечно, в таком случае, авторы браузеров и писатели стандартов должны иметь возможность быстро отреагировать на проблему. Быстрое реагирование на проблему ES5 Object.prototype.toString, а также другие нестыковки, хороший пример того, как разработчики браузеров и другие члены TC39 могут и работают вместе для обеспечения совместимого и интероперабельного веба. Но все начинается с ваших отзывов, которым мы всегда рады.

--
Allen Wirfs-Brock
Microsoft JavaScript Language Architect
Tags:
Hubs:
Total votes 139: ↑116 and ↓23+93
Comments31

Articles