最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 浏览器渲染相关

    正文概述 掘金(蒲月阿七)   2021-02-15   455

    浏览器渲染页面的机制和原理

    现在操作系统比如Mac OS X,UNIX, Linux, Windows等,都是支持“多任务”的操作系统。

    • 单核CPU执行多任务:操作系统轮流让各个任务交替执行,由于CPU执行速度很快,所以我们感觉就像所有任务都在同时执行一样。

    • 多核CPU执行多任务:真正的并行执行多任务只能在多核CPU上实现,但是由于任务数量远远多于多核CPU的核心数量,所以操作系统还是会自动把很多任务轮流调度到每个核心上执行。

    有些进程可能不止同时干一件事,在干多件事的情况下,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程

    多个线程可以同时执行,多线程的执行方式和多进程是一样的,也是由操作系统在多个线程之间快速切换,让每个线程都短暂地交替进行,看起来就像同时执行一样。 浏览器渲染相关

    DOM的回流与重绘

    • 重绘:元素样式的改变(宽高,大小,位置不变)

    • 回流:元素大小或位置发生变化(当页面布局和几何信息发生变化的时候),触发了重新布局,导致渲染树重新计算布局和渲染

    ps:因为回流是根据视口的大小来计算元素的位置和大小的,所以浏览器的窗口尺寸变化也会引发回流。

    • 回流一定会触发重绘,重绘不一定会触发回流。

    优化DOM交互

    • 使用文档碎片减少DOM交互次数。DOM交互越多,性能越慢。
      var list = document.getElementById("myList"),
          item,
          i;
     
      for (i = 0; i <= 10; i++) {
           item.document.createElement("li");
           list.appendChild(item);
           item.appendChild(document.createTextNode(" Item" + i));
      }
    

    上面代码每执行一次for循环都会向DOM插入新的元素,一旦for循环次数很多,那么严重影响代码性能,解决办法就是减少DOM交互。

    可以使用createDocumentFragment方法创建虚拟节点,把要插入DOM的元素先插入该虚拟节点,循环完之后再把虚拟节点插入DOM,虚拟节点是不会渲染出来的,只会渲染它的子节点。改进代码如下:

      var list = document.getElementById("myList");
            fragment = document.createDocumentFragment(),
            i;
     
      for (i = 0; i < 10; i++) {
           item = document.createElement("li");
           fragment.appendChild(item);
           item.appendChild(document.createTextNode("Item" + i));
      }
      
      list.appendChild(fragment);
    

    当我们要批量修改DOM节点的时候,可以将DOM节点隐藏掉,然后进行一系列的修改操作,之后再将其设置为可见,这样就可以最多只进行两次重排。具体的方法如下:

      // 未优化前
      const ele = document.getElementById('test');
      // 一系列dom修改操作
    
      // 优化方案一,将要修改的节点设置为不显示,之后对它进行修改,修改完成后再•显示该节点,从而只需要两次重排
      const ele = document.getElementById('test');
      ele.style.display = 'none';
      // 一系列dom修改操作
      ele.style.display = 'block';
    
      // 优化方案二,首先创建一个文档片段(documentFragment),然后对该片段进行修改,之后将文档片段插入到文档中,只有最后将文档片段插入文档的时候会引起重排,因此只会触发一次重排。。
      const fragment = document.createDocumentFragment();
      const ele = document.getElementById('test');
      // 一系列dom修改操作
      ele.appendChild(fragment);
    
    • 使用innerHTML

    有两种在页面上创建DOM节点的方法:诸如createElement()和appendChild()之类的DOM方法,以及使用innerHTML。当把innerHTML设置为某个值时,后台会创建一个HTML解析器,然后使用内部的DOM调用来创建DOM结构,而非基于JavaScript的DOM调用,由于内部方式是编译好的而非解释执行的,所以执行快的多。

    • 使用事件委托

    把事件绑定在祖先节点,由于有事件冒泡,当事件触发时根据event对象的target属性可以知道具体事件是在那个子元素发生的。从而执行不同的行为。这样就不必每个子节点都绑定事件。

    假设你有一个列表,里面每一个列表项都需要绑定相同的事件,而这个列表可能会频繁的插入和删除。如果按照平常的方法,你只能给每一个列表项都绑定一个事件处理器,并且,每当插入新的列表项的时候,你也需要为新的列表项注册新的事件处理器。这样的话,如果列表项很大的话,就会导致有特别多的事件处理器,造成极大的性能问题。而通过事件委托,我们只需要在列表项的父节点监听这个事件,由它来统一处理就可以了。这样,对于新增的列表项也不需要做额外的处理。而且事件委托的用法其实也很简单:

    function handleClick(target) {
      // 点击列表项的处理事件
    }
    function delegate (e) {
      // 判断目标对象是否为列表项
      if (e.target.nodeName === 'LI') {
        handleClick(e.target);
      }
    }
    const parent = document.getElementById('parent');
    parent.addEventListener('click', delegate);
    
    • css硬件加速(GPU加速)

    比起考虑如何减少回流重绘,我们甚至可以不要回流重绘,css3的 transfrom / opacity / filters / ...这些属性会触发硬件加速,但不会引发回流和重绘,不过可能会导致过多使用后大量占用内存,性能消耗严重,字体模糊等。

    • 动画效果应用到position属性值为absolute或fix的元素上,因为它们脱离文档流。

    • 放弃传统操作dom的模式,采用基于vue/react数据影响视图的模式。

    • 将经常访问到的DOM结点进行缓存

    访问 DOM 会很慢。如果要多次读取某元素的内容,最好将其保存在局部变量中。但记住重要的是,如果稍后你会删除 DOM 的值,则应将变量设置为“null”,不然会导致内存泄漏。

    • 分离读写操作

    offsetTop、offsetLeft、clientTop、clientLeft、scrollWidth、scrollHeight、getComputedStyle...会刷新渲染队列。

    拓展

    link和@import区别

    本质上,这两种方式都是为了加载css文件。

    结论

    强烈建议使用link标签,慎用@import方式。 这样可以避免考虑@import的语法规则和注意事项,避免产生资源文件下载顺序混乱和http请求过多的烦恼。

    区别

    1.从属关系

    @import是 CSS 提供的语法规则,只有导入样式表的作用;link是HTML提供的标签,不仅可以加载 CSS 文件,还可以定义 RSS、rel 连接属性等。

    2.加载顺序

    加载页面时,link标签引入的 CSS 被同时加载;@import引入的 CSS 将在页面加载完毕后被加载。

    3.兼容性区别

    @import是 CSS2.1 才有的语法,故只可在 IE5+ 才能识别;link标签作为 HTML 元素,不存在兼容性问题。

    4.DOM可控性区别

    可以通过 JS 操作 DOM ,插入link标签来改变样式;由于 DOM 方法是基于文档的,无法使用@import的方式插入样式。

    5.权重区别

    CSS 权重优先级顺序简单表示为: !important > 行内样式 > ID > 类、伪类、属性 > 标签名 > 继承 > 通配符

    link标签引入的 CSS 文件中使用@import时,相同样式将被该 CSS 文件本身的样式层叠。

    细节

    在《CSS权威指南》中写道:

    @import一定要写在除@charset外的其他任何 CSS 规则之前,如果置于其它位置将会被浏览器忽略,而且,在@import之后如果存在其它样式,则@import之后的分号是必须书写,不可省略的。

    到此为止,似乎事情都弄清楚了,但是突然又有个疑点浮现出来:

    在讨论区别的时候,不是说加载页面时,link标签引入的 CSS 先于@import引入的 CSS 加载吗,那link标签引入的样式又怎会把@import引入的样式层叠掉呢?

    要回答这个问题,首先我们要一起明确一些有关浏览器的概念:

    浏览器执行过程可以简单分为加载、解析、渲染,这三个步骤。

    加载:根据请求的URL进行域名解析,向服务器发送请求,接收响应文件(如 HTML、JS、CSS、图片等)。

    解析:对加载到的资源(HTML、JS、CSS等)进行语法解析,构建相应的内部数据结构(比如HTML的DOM树,JS对象的属性表,CSS的样式规则等)。

    渲染:构建渲染树,对各个元素进行位置计算、样式计算等,然后根据渲染树完成页面布局及绘制的过程(可以理解为“画”页面元素)。

    这几个过程不是完全孤立的,会有交叉,比如HTML加载后就会进行解析,然后拉取HTML中指定的CSS、JS等。

    现在,我们应该已经了解了加载和渲染的概念,明白它们是两个不同的过程,那么对上文中抛出的疑问继续追问:

    link先于@import加载,是不是也先于@import渲染呢?

    实际上,渲染的动作一般都会执行多次,最后一次渲染,一定是依据之前加载过的所有样式整合后的渲染树进行绘制页面的,已经被渲染过的页面元素,也会被重新渲染。

    那么我们就可以把@import这种导入 CSS 文件的方式理解成一种替换,CSS 解析引擎在对一个 CSS 文件进行解析时,如在文件顶部遇到@import,将被替换为该@import导入的 CSS 文件中的全部样式。

    @import虽然后被加载,却会在加载完毕后置于样式表顶部,最终渲染时自然会被下面的同名样式层叠。

    参考: www.cnblogs.com/my--sunshin…


    起源地下载网 » 浏览器渲染相关

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元