Подтвердить что ты не робот

Как реализованы объекты хоста JavaScript?

Я думал об этом сегодня, и я понял, что у меня нет четкой картины.

Вот некоторые утверждения, которые я считаю правдой (пожалуйста, поправьте меня, если я ошибаюсь):

  • DOM представляет собой набор интерфейсов, определенный W3C.
  • при анализе исходного кода HTML браузер создает дерево DOM с узлами, которые реализуют интерфейсы DOM.
  • Спецификация ECMAScript не имеет ссылок на объекты хоста браузера (DOM, BOM, API HTML5 и т.д.).
  • то, как выполняется DOM, зависит от внутренних элементов браузера и, вероятно, отличается от большинства из них.
  • современные интерпретаторы JS используют JIT для улучшения производительности кода и перевода его на байт-код

Мне интересно, что происходит за кулисами, когда я звоню document.getElementById('foo'). Вызывает ли вызов делегировать собственный код браузера интерпретатором или имеет ли в браузере JS-реализацию всех объектов хоста? Знаете ли вы о какой-либо оптимизации, которую они делают в отношении этого?

Я читал этот обзор внутренних элементов браузера, но ничего об этом не упоминал. Я посмотрю источник Chrome и FF, когда у меня будет время, но я сначала подумал о том, чтобы спросить здесь.:)

4b9b3361

Ответ 1

Все ваши пулевые точки верны, за исключением:

современные интерпретаторы JS используют JIT для улучшения производительности кода и перевода его в байт-код

должен быть "... и перевести его в собственный код". SpiderMonkey (JS-движок в Firefox) долгое время работал в качестве интерпретатора байт-кода до текущей гонки гонок скорости JS.

На мостике Mozilla JS-to-DOM:

Объекты-хосты, как правило, реализуются на С++, хотя есть эксперимент по реализовать DOM в JS. Поэтому, когда веб-страница вызывает document.getElementById('foo'), фактическая работа по извлечению элемента по его идентификатору выполняется в методе С++, как отметил hsivonen.

Конкретный способ вызова базовой реализации С++ зависит от API, а также изменяется со временем (обратите внимание, что я не участвую в разработке, поэтому может быть неправильно о некоторых деталях, здесь сообщение в блоге jst, которое фактически участвовало в создании большей части этого кода):

  • На самом низком уровне каждый движок JS предоставляет API для определения объектов хоста. Например, браузер может вызывать JS_DefineFunctions (как показано в Руководство пользователя SpiderMonkey), чтобы сообщить движку, что всякий раз, когда script вызывает функцию с указанное имя, должен быть вызван обратный вызов C. То же самое для других аспектов объектов хоста (например, перечисление, свойство getters/seters и т.д.).
  • Для основной функциональности ECMAScript и в некоторых сложных случаях DOM механизм JS/браузер использует эти API напрямую для определения объектов хоста и их поведения, но для этого требуется много общего шаблона кода, например. проверка типов параметров, преобразование их в соответствующие типы С++, обработку ошибок и т.д.
  • По причинам, о которых я не буду говорить, скажем исторически, Mozilla сильно использовал XPCOM для многих своих объектов, включая большую часть DOM. Одной из особенностей XPCOM является ее привязка к JS под названием XPConnect. Помимо прочего, XPConnect может принимать определение интерфейса в IDL (например, nsIDOMDocument или, точнее, его скомпилированное представление), выставить объект с указанные свойства в script, а затем, когда script вызывает getElementById, выполните необходимые проверки/преобразования параметров и направьте вызов непосредственно на метод С++ (nsDocument::GetElementById(const nsAString& aId, nsIDOMElement** aReturn))
  • Работа XPConnect была довольно неэффективной: она регистрировала общие функции как обратные вызовы, которые должны выполняться, когда script обращается к объекту хоста, и эти общие функции выяснили, что им нужно делать в каждом конкретном случае динамически. Этот пост о быстрых файлах предлагает вам один пример.
  • "Быстрые заглушки", упомянутые в предыдущей ссылке, - это способ оптимизации времени вызовов JS- > С++ путем торговли некоторым размером кода для него: вместо того, чтобы всегда использовать общие функции С++, которые знают, как совершать какие-либо вызовы, специализированные код автоматически генерируется во время сборки Firefox для предопределенного списка "горячих" вызовов.
  • Позже JIT (tracemonkey в то время) учили генерировать код, вызывающий методы С++ как часть собственного кода, сгенерированного для "горячие" пути в JS. Я не уверен, как работают новые JIT (jaegermonkey) в этом отношении.
  • С "paris bindings" объекты отображаются на веб-странице JS без какой-либо зависимости от XPConnect, вместо этого генерируя весь необходимый код АОкласса на основе WebIDL (вместо IDL XPCOM-эпохи). См. Также сообщения разработчиков, которые работали над этим: jst и khuey. Также см. Как реализуется веб-функция DOM?

Я неясен по деталям из трех последних точек, в частности, поэтому возьмите его с солью.

Самые последние улучшения перечислены в качестве зависимостей ошибка 622298, но я не следую им внимательно.

Ответ 2

JS вызывает методы DOM, такие как getElementById, заставляя JS-сервер вызывать код С++, который реализует DOM. Например, в Firefox вызов заканчивается в nsDocument::GetElementById(const nsAString& aId, nsIDOMElement** aReturn).

Как вы можете видеть, Firefox поддерживает хэш-таблицу, которая отображает идентификаторы в элементы на С++ в качестве оптимизации в этом случае, поэтому она не перемещает все дерево DOM, ища идентификатор.

Ответ 3

DOM реализуется как независимая от языка библиотека практически во всех основных реализациях браузера, что означает ее в другой библиотеке из механизма Javascript. Например, в IE механизм JS реализован в jscript.dll, а DOM - в mshtml.dll. Safari имеет Nitro (JS) и WebCore (DOM). У Chrome есть V8 (JS) и WebCore (DOM), а у Firefox есть SpiderMonkey/TraceMonkey (JS) и Gecko (DOM).

Это означает, что в любое время, когда ваш JS должен получить доступ к DOM, он должен добраться до библиотеки DOM, которая по своей сути медленна из-за всего маршалинга, который должен произойти. Аналогия, которая была использована, - это 2 участка земли, соединенных платной дорожкой, и когда вы прикасаетесь к DOM, вы должны пересечь мост и переправиться обратно - заплатив за проезд.

Ссылки