标签:com 访问 工作 www rom mon 帮助 span lan
当JavaScript访问node.firstChild时,将调用node.h中的Node :: firstChild()。它是如何工作的?我们来看看node.firstChild是如何工作的。
首先,您需要根据规范定义IDL文件:
// node.idl
interface Node : EventTarget {
[...] readonly attribute Node? firstChild;
};
Web IDL的语法在Web IDL规范中定义。 [...]称为IDL扩展属性。一些IDL扩展属性在Web IDL规范中定义,而其他属性是特定于Blink的IDL扩展属性。除了特定于Blink的IDL扩展属性外,IDL文件应以特定的方式编写(即只需从规范中复制和粘贴)。
其次,您需要为Node定义C ++类并为firstChild实现C ++ getter:
class EventTarget : public ScriptWrappable { // All classes exposed to JavaScript must inherit from ScriptWrappable.
...;
};
class Node : public EventTarget {
DEFINE_WRAPPERTYPEINFO(); // All classes that have IDL files must have this macro.
Node* firstChild() const { return first_child_; }
};
在一般情况下,就是这样。构建node.idl时,IDL编译器会自动为Node接口和Node.firstChild生成Blink-V8绑定。自动生成的绑定在// src / out / {Debug,Release} / gen / third_party / blink / renderer / bindings / core / v8 / v8_node.h中生成。当JavaScript调用node.firstChild时,V8在v8_node.h中调用V8Node :: firstChildAttributeGetterCallback(),然后它调用您在上面定义的Node :: firstChild()。
当您编写涉及V8 API的代码时,了解Isolate,Context和World的概念非常重要。它们分别由代码库中的v8 :: Isolate,v8 :: Context和DOMWrapperWorld表示。
Isolate对应于物理线程。 Isolate : physical thread in Blink = 1 : 1。主线程有自己的隔离。工作线程有自己的隔离。
Context对应于全局对象(在Frame的情况下,它是Frame的窗口对象)。由于每个帧都有自己的窗口对象,因此渲染器进程中有多个上下文。当您调用V8 API时,您必须确保您处于正确的上下文中。否则,v8 :: Isolate :: GetCurrentContext()将返回错误的上下文,在最坏的情况下,它将最终泄漏对象并导致安全问题。
World是支持Chrome扩展程序内容脚本的概念。世界与Web标准中的任何内容都不对应。内容脚本希望与网页共享DOM,但出于安全原因,必须将内容脚本的JavaScript对象与网页的JavaScript堆隔离。 (另外一个内容脚本的JavaScript堆必须与另一个内容脚本的JavaScript堆隔离。)为了实现隔离,主线程为网页创建一个主要世界,为每个内容脚本创建一个隔离的世界。主要世界和孤立的世界可以访问相同的C ++ DOM对象,但它们的JavaScript对象是隔离的。通过为一个C ++ DOM对象创建多个V8包装器来实现这种隔离。即每个世界一个V8包装器。
想象一下,主线上有N个世界(一个主要世界+(N - 1)个孤立的世界)。然后一个Frame应该有N个窗口对象,每个窗口对象用于一个世界。上下文是对应于窗口对象的概念。这意味着当我们有M帧和N个世界时,我们有M * N上下文(但是上下文是懒洋洋地创建的)。
对于worker,只有一个世界和一个全球对象。因此,只有一个上下文。
同样,当您使用V8 API时,您应该非常小心使用正确的上下文。否则,您最终会在孤立的世界之间泄漏JavaScript对象并导致安全灾难(例如,A.com的扩展可以操纵来自B.com的扩展)。
在//v8/include/v8.h中定义了很多V8 API。由于V8 API是低级的并且难以正确使用,因此platform / bindings /提供了一堆包装V8 API的辅助类。您应该考虑尽可能多地使用帮助程序类。如果您的代码必须大量使用V8 API,那么这些文件应该放在bindings / {core,modules}中。
V8使用句柄指向V8对象。最常见的句柄是v8 :: Local <>,用于指向机器堆栈中的V8对象。在机器堆栈上分配v8 :: HandleScope后,必须使用v8 :: Local <>。不应在机器堆栈外使用v8 :: Local <>:
void function() {
v8::HandleScope scope;
v8::Local<v8::Object> object = ...; // This is correct.
}
class SomeObject : public GarbageCollected<SomeObject> {
v8::Local<v8::Object> object_; // This is wrong.
};
每个C ++ DOM对象(例如,Node)具有其对应的V8包装器。准确地说,每个C ++ DOM对象每个世界都有相应的V8包装器。
V8包装器对其对应的C ++ DOM对象具有强引用。但是,C ++ DOM对象只有对V8包装器的弱引用。因此,如果您希望将V8包装器保持活动一段时间,则必须明确地执行此操作。否则,V8包装器将过早收集,V8包装器上的JS属性将丢失。
div = document.getElementbyId("div");
child = div.firstChild;
child.foo = "bar";
child = null;
gc(); // If we don‘t do anything, the V8 wrapper of |firstChild| is collected by the GC.
assert(div.firstChild.foo === "bar"); //...and this will fail.
如果我们不做任何事情,那么孩子会被GC收集,因此child.foo会丢失。为了使div.firstChild的V8包装器保持活动状态,我们必须添加一种机制,“只要div所属的DOM树可以从V8到达,就可以使div.firstChild的V8包装器保持活动状态”。
标签:com 访问 工作 www rom mon 帮助 span lan
原文地址:https://www.cnblogs.com/bigben0123/p/13175909.html