浏览器成、线程及event loop

浏览器成

图片 1

User interface: a. Every part of the browser display, except the window.
b. The address bar, back/forward button, bookmarking menu, etc.

Browser Engine: marshals actions between the UI and the rendering
engine. This provides a high-level interface to the Rendering Engine.
The Browser Engine provides methods to initiate the loading of a URL and
other high-level browsing actions (reload, back, forward). The Browser
Engine also provides the User interface with various messages relating
to error messages and loading progress.

Rendering engine(渲染引擎/内核) : a. Parse HTML and CSS. b. Display
parsed content on the screen.

JavaScript interpreter: Used to parse and execute JavaScript code.

浏览器的线程

浏览器是多线程的,它们于内核制控下相互配合以保障同步。一个浏览器至少实现三独常屯兵线程:JavaScript引擎线程,GUI渲染线程,浏览器事件触发线程。

1)
javascript引擎是因事件驱动单线程履之(可以改DOM,简单化处理了),必须符合ECMAScript规范。JS引擎一向等候在event
loop中任务之赶来,然后加以处理(唯有当前函数执行栈执行完毕,才会失掉任务队列中拿到任务履行)。浏览器无论何时都只有出一个JS线程在运行JS程序。

2)
UI渲染线程负责渲染浏览器界面,当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就碰面履行。不过
GUI渲染线程与JS引擎是轧的,当JS引擎执行时GUI线程会给高悬于,JS对页面的操作就GUI的更新为会见被保留于一个排中,等到JS引擎空闲时才起会吃实施。这虽是JS阻塞页面加载。

3)
事件触发线程,当一个轩然大波给硌时欠线程会将事件续加至任务队列的队尾,等待JS引擎的拍卖。这个事件可以自JavaScript引擎当前执行的代码块调用set提姆(Tim)eout/ajax添加一个职责,也足以自浏览器其他线程如鼠标点击添加的天职。但由JS的单线程关系,所有这多少个事件都得排队等待JS引擎处理。

 “任务队列”是一个事变的队(也堪清楚成音信队列),当浏览器的另线程完触发一样件职责时,就以js引擎的”任务队列”中上加一个事件/任务,异常js引擎的函数执行栈空闲时即使相会读取任务队列的风波,并实施该事件对应的回调函数。队列中后的职责要等前的天职执行完毕才会让实践。该过程会直接循环不歇,如下图所示:

图片 2

Event loops

HTML规范遭发出要求浏览器实现。简单总计如下:
为协调事件,用户接口,脚本,渲染,网络等,浏览器必须使event loops。有对 browsing
contexts和 workers的两种类型。An event loop has one or more task
queues.来自同一个task source的富有tasks必须放入同一个task
queue。日常有4遇到task source:DOM manipulation task source,user
interaction task source,networking task source和history traversal task
source。同一个task queue是按先进先出顺序执行之。浏览器可因task
queue中task source的不等,给予task queue差的事先级。比如为及时响应,the
user agent could then give keyboard and mouse events preference over
other tasks three quarters of the time。即由浏览器决定挑啦一个task
queue中的先河task执行。
另外Each event loop has a microtask queue. Microtask execute in order,
and are
executed
:

  • after every callback, as long as no other JavaScript is
    mid-execution;
  • at the end of each task.

task分为两近似:
macro-task:script( js codes as a whole in script tag),setTimeout,
setInterval, setImmediate, requestAnimationFrame, I/O, UI rendering;
micro-task:process.nextTick, Promises, Object.observe,
MutationObserver.

js引擎会管task push到相应的macrotask queue(即task queue)或microtask
queue中。每当event loop的一个合中,会优先从macrotask
queue中取出队首的职责进展实践;执行了后,再逐一执行microtask
queue中的有任务;假设在执行进程被上加了新的microtask,则会于时下底合中继续执行,直到所有mircotask执行完毕才上下一个event
loop回合。

An event loop must continually run through the following steps for
as long as it exists:

  1. select the oldest task(task A) in task queues.If task A is
    null(means task queues is empty),jump to step 5(microtasks steps)
  2. set “currently running task” to “task A”
  3. run “task A”(means run the callback function)
  4. set “currently running task” back to null,and remove “task A” from
    its task queue
  5. perform microtask queue
    • (a).select the oldest task(task x) in microtask queue
    • (b).if task x is null(means microtask queues is empty),jump to
      step (g)
    • (c).set “currently running task” to “task x”
    • (d).run “task x”
    • (e).set “currently running task” to null,remove “task x” from
      the microtask queue
    • (f).select next oldest task in microtask queue,jump to step(b)
    • (g).finish microtask queue;
  6. update rendering
  7. next routnd:jump to step 1

microtask执行时过长会导致macotask任务之梗塞,导致UI渲染的梗塞。nodejs的process.nextTick限制1000单tick任务,以要macrotask得以实施。

案例解析1: 

//promises come from ECMAScript rather than HTML
setTimeout(function(){console.log(4)},0);
new Promise(function(resolve){
    console.log(1)
    for( var i=0 ; i<10000 ; i++ ){
        i==9999 && resolve()
    }
    console.log(2)
}).then(function(){
    console.log(5)
})then(function(){
    console.log(6)
});
console.log(3);
//整个js代码是script task,属于macrotask,会在当前task queue中执行,在执行过程中碰到setTimeout,会push到task queue中,但要等下一回合执行;第一个then()属于microtask,在本回合执行,返回undefined,第二个then()也会在当前回合执行

 案例解析2:js线程平昔推行,stack就无呢空,浏览器就是无机会取task
queue中之UI render任务立异页面。chrome dev tools的断点调试会影响event
loop实时更新UI.

图片 3

Render queue:浏览器在1s惨遭渲染页面60不成,每16ms就会合往Render
queue中添加一个UI
render任务。不过浏览器唯有以stack为空时才生机遇执行该任务。通过set提姆(Tim)eout(cb,0)将任务分割,就是搭UI
render 任务为实践之时,改善用户体验。

足拿统计量大的天职通过set提姆(Tim)eout分割成三个小任务,这样浏览器就是暴发工夫执行UI线程。不过不佳的地点是算所要费的小运会晤再也增长。分析performance,想艺术改良代码(单次小任务中执更多的盘算)以退cpu
idle的占据相比较。

事件冒泡再一次实施的回调仍属于同一个task:

图片 4

经js代码触发click事件(targetEle.click())会招在举办回调的闲暇仍在script
task中,故stack不会师呢空,阻塞microtask执行。