chromium blink core outline

chromium blink core outline_51CTO博客_switchyomega_chromium.crx

多进程架构,有一个浏览器进程和N个沙盒渲染器进程,Blink在沙盒渲染中运行。浏览器选项卡、iframe可共享同个渲染器进程。

沙箱运行:在沙箱中,须通过父浏览器进程来调度使用资源(文件访问、网络、音视频播放、用户配置文件读取(cookie,密码)等。Blink将浏览器进程抽象为一组服务,使用Mojo与服务、浏览器进程交互。

渲染进程中的线程

1个主线程:运行JavaScript、DOM、CSS、样式,布局计算
N个工作线程:运行Web Worker,ServiceWorker,Worklet
内部线程:Blink和V8会创建几个线程处理web audio,数据库,GC等
跨线程通信:您必须使用PostTask API使用消息传递。不鼓励共享内存编程,除非出于性能原因需要使用它的几个地方。这就是为什么你在Blink代码库中看不到很多MutexLock的原因。

Page,Frame,Document,ExecutionContext和DOMWindow是以下概念:

Page:页面对应于选项卡的概念(如果未启用下面解释的OOPIF)。每个渲染器进程可能包含多个选项卡。
Frame:帧对应于帧的概念(主帧或iframe)。每个页面可能包含一个或多个以树形层次结构排列的框架。1:n
DOMWindow对应于JavaScript中的windows对象 。每个Frame只有一个DOMWindow。1:1
Document对应于JavaScript中的window.document对象。每个iframe只有一个Document。1:1
ExecutionContext是一个抽象Document(用于主线程)和WorkerGlobalScope(用于工作线程)的概念。


Renderer process : Page = 1 : N 单进程的情况下, 多进程的情况下需要根据模式区分。

Page : Frame = 1 : M

扫描二维码关注公众号,回复: 15075980 查看本文章

Frame : DOMWindow : Document (or ExecutionContext) = 1 : 1 : 1

page是一个tab或者chromium扩展中的后台页面。

执行上下文ExecutionContext是JS的执行上下文。一个page对应有多个:每个frame附加到DOM后,都会有个隐含的执行上下文​​;扩展有另外的执行上下文。​​

DOMWindow(js windows对象) 和Document (js的window.document)(or ExecutionContext) 是JS中用来交互控制的。

渲染器进程的本地帧由LocalFrame表示,而渲染器进程不是本地的帧由RemoteFrame表示。

从主框架的角度来看,主框架是LocalFrame,<iframe>是RemoteFrame。从<iframe>的角度来看,主框架是RemoteFrame,<iframe>是LocalFrame。

LocalFrame和RemoteFrame(可能存在于不同的渲染器进程中)之间的通信通过浏览器进程处理。

V8 API的代码时,了解Isolate,Context和World的概念非常重要。它们分别由代码库中的v8 :: Isolate,v8 :: Context和DOMWrapperWorld表示。

Isolate对应于物理线程。 Isolate : physical thread in Blink = 1 : 1。主线程有自己的隔离。工作线程有自己的隔离。

一个V8的实例被称作Isolate,每一个isolate都有独立GC的堆栈空间。这就意味着一个Isolate中的JavaScript对象不能直接访问另一个Isolate中的对象。

在Chrome中,每个渲染进程都有一个V8 Isolate,所有被同一个渲染进程处理的站点的JavaScript代码在同一个Isolate中运行。但对于Web worker,每一个worker则拥有自己的Isolate。

在Isolate中,存在一个或多个JavaScript上下文环境(JavaScript content)。Chrome为每个iframe创建一个JavaScript环境。此外,每个Chrome extension对于一个iframe都有自己的JavaScript环境。Blink通常使用ScriptState对象作为JavaScript环境的引用,blink::ScriptState与v8::Context有着1 : 1的关系。(参考:​ ​https://zhuanlan.zhihu.com/p/279920830​​)

Context对应于全局对象(在Frame的情况下,它是Frame的窗口对象)。由于每个帧都有自己的窗口对象,因此渲染器进程中有多个上下文。当您调用V8 API时,您必须确保您处于正确的上下文中。否则,v8 :: Isolate :: GetCurrentContext()将返回错误的上下文,在最坏的情况下,它将最终泄漏对象并导致安全问题。

World是支持Chrome扩展程序内容脚本的概念。世界与Web标准中的任何内容都不对应。内容脚本希望与网页共享DOM,但出于安全原因,必须将内容脚本的JavaScript对象与网页的JavaScript堆隔离。 (另外一个内容脚本的JavaScript堆必须与另一个内容脚本的JavaScript堆隔离。)为了实现隔离,主线程为网页创建一个主要世界,为每个内容脚本创建一个隔离的世界。主要世界和孤立的世界可以访问相同的C ++ DOM对象,但它们的JavaScript对象是隔离的。通过为一个C ++ DOM对象创建多个V8包装器来实现这种隔离。即每个世界一个V8包装器。

Context,World和Frame之间有什么关系?

想象一下,主线上有N个世界(一个主要世界+(N - 1)个孤立的世界)。然后一个Frame应该有N个窗口对象,每个窗口对象用于一个世界。上下文是对应于窗口对象的概念。这意味着当我们有M帧和N个世界时,我们有M * N上下文(但是上下文是懒洋洋地创建的)。

对于worker,只有一个世界和一个全球对象。因此,只有一个上下文。

同样,当您使用V8 API时,您应该非常小心使用正确的上下文。否则,您最终会在孤立的世界之间泄漏JavaScript对象并导致安全灾难(例如,A.com的扩展可以操纵来自B.com的扩展)。

作者:JeffMony

链接:https://www.jianshu.com/p/2a2424bdc057

来源:简书

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

浏览器的渲染进程是多线程的(这点如果不理解,请回头看进程和线程的区分)

终于到了线程这个概念了????,好亲切。那么接下来看看它都包含了哪些线程(列举一些主要常驻线程):

1.GUI渲染线程

负责渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等。

当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行

注意,GUI渲染线程与JS引擎线程是互斥的,当JS引擎执行时GUI线程会被挂起(相当于被冻结了),GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。

2.JS引擎线程

也称为JS内核,负责处理Javascript脚本程序。(例如V8引擎)

JS引擎线程负责解析Javascript脚本,运行代码。

JS引擎一直等待着任务队列中任务的到来,然后加以处理,一个Tab页(renderer进程)中无论什么时候都只有一个JS线程在运行JS程序

同样注意,GUI渲染线程与JS引擎线程是互斥的,所以如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞。

3.事件触发线程

归属于浏览器而不是JS引擎,用来控制事件循环(可以理解,JS引擎自己都忙不过来,需要浏览器另开线程协助)

当JS引擎执行代码块如setTimeOut时(也可来自浏览器内核的其他线程,如鼠标点击、AJAX异步请求等),会将对应任务添加到事件线程中

当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理

注意,由于JS的单线程关系,所以这些待处理队列中的事件都得排队等待JS引擎处理(当JS引擎空闲时才会去执行)

4.定时触发器线程

传说中的setInterval与setTimeout所在线程

浏览器定时计数器并不是由JavaScript引擎计数的,(因为JavaScript引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确)

因此通过单独线程来计时并触发定时(计时完毕后,添加到事件队列中,等待JS引擎空闲后执行)

注意,W3C在HTML标准中规定,规定要求setTimeout中低于4ms的时间间隔算为4ms。

5.异步http请求线程

在XMLHttpRequest在连接后是通过浏览器新开一个线程请求

将检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件,将这个回调再放入事件队列中。再由JavaScript引擎执行。

GUI渲染线程与JS引擎线程互斥
由于JavaScript是可操纵DOM的,如果在修改这些元素属性同时渲染界面(即JS线程和UI线程同时运行),那么渲染线程前后获得的元素数据就可能不一致了。

因此为了防止渲染出现不可预期的结果,浏览器设置GUI渲染线程与JS引擎为互斥的关系,当JS引擎执行时GUI线程会被挂起,

GUI更新则会被保存在一个队列中等到JS引擎线程空闲时立即被执行。

JS阻塞页面加载
从上述的互斥关系,可以推导出,JS如果执行时间过长就会阻塞页面。

譬如,假设JS引擎正在进行巨量的计算,此时就算GUI有更新,也会被保存到队列中,等待JS引擎空闲后执行。

然后,由于巨量计算,所以JS引擎很可能很久很久后才能空闲,自然会感觉到巨卡无比。

所以,要尽量避免JS执行时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。

WebWorker,JS的多线程?
前文中有提到JS引擎是单线程的,而且JS执行时间过长会阻塞页面,那么JS就真的对cpu密集型计算无能为力么?

所以,后来HTML5中支持了Web Worker。

MDN的官方解释是:

Web Worker为Web内容在后台线程中运行脚本提供了一种简单的方法。线程可以执行任务而不干扰用户界面一个worker是使用一个构造函数创建的一个对象(e.g. Worker()) 运行一个命名的JavaScript文件 这个文件包含将在工作线程中运行的代码; workers 运行在另一个全局上下文中,不同于当前的window因此,使用window快捷方式获取当前全局的范围 (而不是self) 在一个 Worker 内将返回错误复制代码

这样理解下:

创建Worker时,JS引擎向浏览器申请开一个子线程(子线程是浏览器开的,完全受主线程控制,而且不能操作DOM)

JS引擎线程与worker线程间通过特定的方式通信(postMessage API,需要通过序列化对象来与线程交互特定的数据)

所以,如果有非常耗时的工作,请单独开一个Worker线程,这样里面不管如何翻天覆地都不会影响JS引擎主线程,

只待计算出结果后,将结果通信给主线程即可,perfect!

而且注意下,JS引擎是单线程的,这一点的本质仍然未改变,Worker可以理解是浏览器给JS引擎开的,专门用来解决那些大量计算问题。

其它,关于Worker的详解就不是本文的范畴了,因此不再赘述。

WebWorker与SharedWorker
既然都到了这里,就再提一下SharedWorker(避免后续将这两个概念搞混)

WebWorker只属于某个页面,不会和其他页面的Render进程(浏览器内核进程)共享

所以Chrome在Render进程中(每一个Tab页就是一个render进程)创建一个新的线程来运行Worker中的JavaScript程序。

SharedWorker是浏览器所有页面共享的,不能采用与Worker同样的方式实现,因为它不隶属于某个Render进程,可以为多个Render进程共享使用

所以Chrome浏览器为SharedWorker单独创建一个进程来运行JavaScript程序,在浏览器中每个相同的JavaScript只存在一个SharedWorker进程,不管它被创建多少次。

看到这里,应该就很容易明白了,本质上就是进程和线程的区别。SharedWorker由独立的进程管理,WebWorker只是属于render进程下的一个线程

作者:Jony0114

链接:https://www.jianshu.com/p/f1e5ad3b4afb

来源:简书

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Frame和WebFrame
Frame和WebFrame是一一对应的关系,Frame可以通过client找到WebFrame, WebFrame也可以通过Client找到Frame。

其他的Web**封装的类可以参考这个

 IFrame, window, document三个互相获取

LocalFrame* frame = node_->GetDocument().GetFrame();
  if (frame && frame->DomWindow())//frame中获取domwindow
    eventTiming = EventTiming::Create(frame->DomWindow(), *event_);
  event_->GetEventPath().EnsureWindowEventContext();  //从事件中获取domWindow发送事件

//从上下文发送事件
auto* window = To<LocalDOMWindow>(GetExecutionContext());
window->DispatchEvent(*Event::Create(event_name));

frame中获取domwindow            发送事件 
    frame_ ? frame_->DomWindow()
    frame_->DomWindow() is null??
   frame_->DomWindow()->DispatchEvent(unload_event, this);

获取frame    
1,获取当前frame
LocalFrame* Document::ExecutingFrame() {
  LocalDOMWindow* window = ExecutingWindow();
  if (!window)
    return nullptr;
  return window->GetFrame();
}

2,找到顶层frame。frame都带着window和document js对象
Frame& top = GetFrame()->Tree().Top();
  KURL top_document_url;
  auto* top_local_frame = DynamicTo<LocalFrame>(&top);

3,从domwindow获取frame
1.
LocalDOMWindow* executing_window = ExecutingWindow();
1.
LocalFrame* frame = executing_window->GetFrame();

frame中获取document js对象
frame_->GetDocument()
 


 

localDomWindow发送事件,原型:DispatchEventResult LocalDOMWindow::DispatchEvent(Event& event,EventTarget* target)

 DispatchEvent(*Event::Create(event_type_names::kLanguagechange));

DispatchEvent(*PageTransitionEvent::Create(event_type_names::kPageshow,false /* persisted */),document_.Get());

 
-----------------------------------
chromium blink core outline
https://blog.51cto.com/u_15057855/4536130

猜你喜欢

转载自blog.csdn.net/juruiyuan111/article/details/128427393