标签:控制 有一个 绘制 cti timeout 误差 tab settime 系统
首先我们应该先知道浏览器内核渲染进程是由多线程组成的,其中主要包括以下几个
1、GUI渲染线程
。主要负责渲染浏览器界面,解析HTML和CSS,构建DOM树和RenderObject树,布局和绘制等
。当页面需要重绘或者由于某种操作引发页面回流时,该线程就会执行
。注意,GUI渲染线程和JS引擎线程是互斥的,当JS引擎线程运行的时候,GUI渲染线程就会被挂起,GUI更新会被保存在一个队列中,等待JS引擎空闲下来立即执行
2、JS引擎线程
。又称为JS内核,主要负责处理javascript脚本程序
。JS引擎负责解析javascript脚本,运行代码
。JS引擎一直等待着任务队列中任务的到来,然后加以处理,一个Tab页面中无论什么时候都只有一个js线程在执行js程序
。同样,JS引擎线程和GUI渲染线程是互斥的,所以如果JS线程执行的时间过长,这样会造成页面的渲染不连贯,导致页面渲染加载阻塞
3、事件触发线程
。该线程归属于浏览器而不是JS引擎线程,用来控制事件循环。(可以这样理解,JS引擎自己都忙不过来,需要浏览器另开线程协助)
。当JS引擎执行代码块 如setTimeOut(也可来自浏览器内核的其他线程,如鼠标点击,AJAX异步请求等)时,会把对应的任务添加到事件触发线程中
。当对应的事件符合触发条件被触发时,该线程会把该事件添加到待处理的任务队列的队尾,等待JS引擎处理
。由于JS引擎是单线程的,所以这些待处理任务队列中的事件都得排队等待JS引擎处理(JS引擎空闲时才会去执行)
4、定时触发器线程
。传说中的setTimeOut和setInterval所在的线程
。浏览器定时计数器并不是由javascript引擎计数的(因为JS引擎是单线程的,如果线程处于阻塞状态就会影响计时的准确性)
。因为通过单独的线程来计时并触发定时(计时完毕后,添加到事件队列中,等待JS引擎空闲后执行)
。需要注意,W3C在HTML标准中规定,setTimeOut小于4ms的时间间隔算为4ms
5、异步http请求线程
。在XMLHttpRequest连接后是通过浏览器新开一个线程请求
。在检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件,将这个回调再放入事件队列中,由js引擎空闲时执行
我们都知道JS引擎是单线程的,这是因为JS的作用主要是与用户互动,以及操作DOM,这决定了他只能是单线程的,否则会带来很多同步的问题,假如JS有两个线程,同一时间一个线程再某个DOM节点上添加东西,一个线程再删除该DOM节点,这时候就会出现问题
然后我们还需要理解一些概念:
.JS分为同步任务和异步任务
1.同步任务都在主线程上执行,形成一个执行栈
2.主线程之外,事件触发线程管理着一个任务队列,只要异步任务有了结果,就会在任务队列中添加一个事件
3.一旦执行栈中所有同步任务执行完毕,此时,JS引擎空闲,系统就会读取任务队列,将可执行的异步任务添加到可执行栈中,开始执行
如此循环上面的步骤
看到这里我们大概明白了,为什么setTimeOut推入的事件没有在规定的时间执行,这是因为,当它推入到事件队列中时,主线程还没有空闲,JS引擎还在执行主线程的任务,所以自然会有误差
关于定时器:
上述事件循环机制的核心是:JS引擎线程和事件触发线程
但事件上还有一些隐藏的细节,譬如,调用setTimeOut后,是如何等待特定时间后才添加到事件队列中的?
是JS引擎检测的么?当然不是了。它是由定时器线程控制
为什么要单独的定时器线程?因为JS引擎是单线程的,如果处于阻塞线程状态就会影响计时的准确,因此很有必要单独开一个线程来计时
什么时候会用到定时器线程?当使用setTimeOut或setInterval时,他需要定时器线程计时,计时完成后就会将特定的事件推入事件队列中。
譬如:
setTimeout(function(){
console.log(‘hello!‘);
},1000);
这段代码的作用是1000毫秒计时完成后(由定时器线程计时),将回调函数推入事件队列中,等待主线程执行
setTimeout(function(){
console.log(‘hello!‘);
},0);
console.log(‘begin‘);
这段代码的效果是最快的时间内将回调函数推入事件队列中,等待主线程执行
注意
执行结果是先begin后hello!
虽然代码的本意是0毫秒后就推入事件队列,但是W3C在HTML标准中规定,要求setTimeout中低于4ms的时间间隔算为4ms
就算不等待4ms,就算假设0毫秒就推入事件队列,也会先执行begin(因为只有可执行栈内空了后才会主动读取事件队列)
标签:控制 有一个 绘制 cti timeout 误差 tab settime 系统
原文地址:https://www.cnblogs.com/lvruifang/p/9406793.html