JavaScript 宿主对象是如何实现的? [英] How are JavaScript host objects implemented?

查看:21
本文介绍了JavaScript 宿主对象是如何实现的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我今天正在考虑这个问题,但我意识到我这里没有清晰的图片.

I was thinking about this today and I realized I don't have a clear picture here.

以下是我认为正确的一些陈述(如果我错了,请纠正我):

Here are some statements I think to be true (please correct me if I'm wrong):

  • DOM 是 W3C 指定的接口集合.
  • 在解析 HTML 源代码时,浏览器会创建一个 DOM 树,其中包含实现 DOM 接口的节点.
  • ECMAScript 规范没有引用浏览器主机对象(DOM、BOM、HTML5 API 等).
  • DOM 的实际实现方式取决于浏览器内部结构,并且其中大多数可能有所不同.
  • 现代 JS 解释器使用 JIT 来提高代码性能并将其转换为字节码

当我调用 document.getElementById('foo') 时,我很好奇幕后发生了什么.调用是否由解释器委托给浏览器本机代码,或者浏览器是否具有所有主机对象的 JS 实现?你知道他们在这方面做了什么优化吗?

I am curious about what happens behind the scenes when I call document.getElementById('foo'). Does the call get delegated to browser native code by the interpreter or does the browser have JS implementations of all host objects? Do you know about any optimizations they do in regard to this?

我阅读了这个浏览器内部概览,但没有提及任何内容对这个.有时间我会翻翻Chrome和FF源码,不过想到这里先问一下.:)

I read this overview of browser internals but it didn't mention anything about this. I will look through the Chrome and FF source when I have time, but I thought about asking here first. :)

推荐答案

你所有的要点都是正确的,除了:

All of your bullet points are correct, except:

现代 JS 解释器使用 JIT 来提高代码性能并将其翻译成字节码

modern JS interpreters use JIT to improve the code performance and translate it to bytecode

应该是...并将其翻译成本机代码".SpiderMonkey(Firefox 中的 JS 引擎)在当前的 JS 速度军备竞赛之前作为字节码解释器工作了很长时间.

should be "...and translate it to native code". SpiderMonkey (the JS engine in Firefox) worked as a bytecode interpreter for a long time before the current JS speed arms race.

关于 Mozilla 的 JS-to-DOM 桥:

On Mozilla's JS-to-DOM bridge:

宿主对象通常是用 C++ 实现的,尽管正在进行一项实验以在 JS 中实现 DOM.因此,当网页调用 document.getElementById('foo') 时,通过其 ID 检索元素的实际工作是在 C++ 方法中完成的,正如 hsivonen 指出的那样.

The host objects are typically implemented in C++, though there is an experiment underway to implement DOM in JS. So when a web page calls document.getElementById('foo'), the actual work of retrieving the element by its ID is done in a C++ method, as hsivonen noted.

调用底层 C++ 实现的具体方式取决于 API 并且随着时间的推移也会发生变化(请注意,我不参与开发,因此某些细节可能有误,这里是 jst 的博文,他实际上参与了大部分代码的创建):

The specific way the underlying C++ implementation gets called depends on the API and also changed over time (note that I'm not involved in the development, so might be wrong about some details, here's a blog post by jst, who was actually involved in creating much of this code):

  • 在最底层,每个 JS 引擎都提供 API 来定义宿主对象.例如,浏览器可以调用 JS_DefineFunctions(如 SpiderMonkey 用户指南 中所示)让引擎知道每当脚本调用具有指定名称的函数时,都应该调用提供的 C 回调.宿主对象的其他方面也是如此(例如枚举、属性 getter/setter 等)
  • 对于核心 ECMAScript 功能和在一些棘手的 DOM 情况下,JS 引擎/浏览器直接使用这些 API 来定义宿主对象及其行为,但它需要大量常见的样板代码,例如检查参数类型,将它们转换为适当的 C++ 类型,错误处理等.
  • 出于我不会讨论的原因,我们假设从历史上看,Mozilla 大量使用了 XPCOM 对于它的许多对象,包括大部分 DOM.XPCOM 的一个特性是它与称为 XPConnect 的 JS 的绑定.除此之外,XPConnect 可以采用 IDL 中的接口定义(例如 nsIDOMDocument;或更准确地说是它的编译表示),将具有指定属性的对象暴露给脚本,然后,当脚本调用 getElementById 时,执行必要的参数检查/转换并将调用直接路由到 C++ 方法(<代码>nsDocument::GetElementById(const nsAString& aId, nsIDOMElement** aReturn))
  • XPConnect 的工作方式非常低效:它将通用函数注册为要在脚本访问宿主对象时执行的回调,而这些通用函数会动态地找出在每个特定情况下它们需要做什么.这篇关于 quickstubs 的博文 向您介绍了一个例子.莉>
  • 上一个链接中提到的快速存根"是一种通过为它交换一些代码大小来优化 JS->C++ 调用时间的方法:而不是总是使用知道如何进行任何类型调用的通用 C++ 函数,专门的代码在 Firefox 构建时自动生成,用于预定义的热"调用列表.
  • 后来在 JIT(当时的 tracemonkey)被教导生成调用 C++ 的代码方法 作为为 JS 中的热"路径生成的本机代码的一部分.我不确定较新的 JIT (jaegermonkey) 在这方面是如何工作的.
  • 使用 "paris bindings" 对象 暴露于网页JS,不依赖XPConnect,而是基于WebIDL生成所有必要的胶JSClass代码(而不是 XPCOM 时代的 IDL).另请参阅从事此工作的开发人员的帖子:jstkhuey.另请参阅 Web 公开的 DOM 是如何实现的?
  • At the lowest level every JS engine provides APIs to define host objects. For example, the browser can call JS_DefineFunctions (as demonstrated in the SpiderMonkey User Guide) to let the engine know that whenever script calls a function with the specified name, a provided C callback should be called. Same for other aspects of the host objects (e.g. enumeration, property getters/setters, etc.)
  • For the core ECMAScript functionality and in some tricky DOM cases the JS engine/the browser uses these APIs directly to define host objects and their behaviors, but it requires a lot of common boilerplate code for e.g. checking parameter types, converting them to the appropriate C++ types, error handling etc.
  • For reasons I won't go into, let's say historically, Mozilla made heavy use of XPCOM for many of its objects, including much of the DOM. One feature of XPCOM is its binding to JS called XPConnect. Among other things, XPConnect can take an interface definition in IDL (such as nsIDOMDocument; or more precisely its compiled representation), expose an object with the specified properties to the script, and later, when a script calls getElementById, perform the necessary parameter checks/conversions and route the call directly to a C++ method (nsDocument::GetElementById(const nsAString& aId, nsIDOMElement** aReturn))
  • The way XPConnect worked was quite inefficient: it registered generic functions as callbacks to be executed when a script accesses a host object, and these generic functions figured out what they needed to do in every particular case dynamically. This post about quickstubs walks you through one example.
  • "Quick stubs" mentioned in the previous link is a way to optimize JS->C++ calls time by trading some code size for it: instead of always using generic C++ functions that know how to make any kind of call, the specialized code is automatically generated at the Firefox build time for a pre-defined list of "hot" calls.
  • Later on the JIT (tracemonkey at that time) was taught to generate the code calling C++ methods as part of the native code generated for "hot" paths in JS. I'm not sure how the newer JITs (jaegermonkey) work in this regard.
  • With "paris bindings" the objects are exposed to webpage JS without any reliance on XPConnect, instead generating all the necessary glue JSClass code based on WebIDL (instead of XPCOM-era IDL). See also posts by developers who worked on this: jst and khuey. Also see How is the web-exposed DOM implemented?

我对最后三点的细节特别模糊,所以请谨慎对待.

I'm fuzzy on details of the three last points in particular, so take it with a grain of salt.

最近的改进被列为 bug 622298 的依赖项,但我不要密切关注他们.

The most recent improvements are listed as dependencies of bug 622298, but I don't follow them closely.

这篇关于JavaScript 宿主对象是如何实现的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆