全局Window对象创建与Realm依赖死锁及实现细节技术问询
问题背景
当浏览器打开新窗口或标签页时,会创建新的browsing context。根据规范,创建新browsing context会触发创建新JavaScript realm的流程,最终调用ECMAScript的InitializeHostDefinedRealm操作,要求以新的Window对象作为全局对象,WindowProxy作为全局this值。
而创建Window这类platform object时,需要先创建对应的interface object(比如Window函数对象)来生成Window.prototype;同时创建platform object的流程又依赖realm的[[GlobalObject]]属性(用于检查接口成员的暴露规则)。但InitializeHostDefinedRealm中,[[GlobalObject]]要在宿主创建Window对象后才设置,这就出现了逻辑矛盾。
问题1:InitializeHostDefinedRealm中的全局对象创建死锁如何解决?
规范描述的是逻辑上的步骤顺序,浏览器实现时会通过分阶段创建+内部临时状态绕过这个死锁:
- 先创建空的realm实例,此时
[[GlobalObject]]暂不设置; - 搭建
Window对象的基础骨架(不立即填充所有暴露成员),此时暂时跳过依赖[[GlobalObject]]的Exposed检查,或用内部临时标记替代; - 将这个基础
Window对象赋值给realm的[[GlobalObject]]属性; - 最后基于已绑定全局对象的realm,补全
Window对象的所有成员(包括需要检查Exposed规则的部分)。
本质是把全局对象的创建拆成“先关联realm,再完善内容”两步,避开规范描述的逻辑死锁。
问题2:创建browsing context时,Window对象的创建顺序是怎样的?
是的,浏览器确实遵循先创建Window interface object,再创建window platform object的顺序:
- 先执行创建interface object的流程,生成
Window函数对象和对应的Window.prototype原型对象——这是创建platform object的前提,因为platform object需要继承自对应的接口原型; - 再基于已有的
Windowinterface object和原型,创建window这个platform object实例,之后将其关联到realm的[[GlobalObject]]。
虽然HTML规范的创建browsing context步骤没明确写这个顺序,但Web IDL关于platform object的创建规则要求必须先有对应的interface object和原型,因此这是必然的实现顺序。
内容的提问来源于stack exchange,提问作者Magnus

