1. 单核cpu执行多任务·:操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换到任务2,任务2执行0.01秒,在切换到任务3,由于CPU的执行速度实在太快了,我们感觉就像所有任务都在执行一样<br /> 多核CPU执行多任务:真正的并行执行多任务只能在多核cpu上实现,但是,由于任务数量远远多于CPU的核心数量,所以,操作系统也会自动把很多任务轮流调度到每个核心上执行<br /> 有些进程不止同时干一件事,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的“子任务”成 为线程<br /> 多个线程可以同时执行,多线程的执行方式和多进程是一样的,也是有操作系统在多个线程之间快速切换,让每个线程都短暂的交替运行,看起来就像同时执行一样

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

image.pngimage.png

  1. 解析HTML,生成DOM树,解析CSS,生成CSSDOM树
  2. 将DOM和CSSDOM树结合,生成渲染树(render Tree)
  3. Layout(回流):根据生成的渲染树,计算他们在设备视口(viewport)内的确切位置和大小,这个计算的阶段就是回流
  4. Painting(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素
  5. Display将像素发送给GPU,展示在页面上

    DOM的重绘和回流

    重绘:是在一个元素的外观被改变所触发的浏览器行为,浏览器会根据元素的新属性重新绘制,使元素呈现新的外观,(即元素样式的改变,但是宽高,大小,位置等不改变)。

回流(重排):当dom变化影响元素的几何属性(宽,高改变等),浏览器此时需要重新计算元素几何属性并且页面中的其他元素的几何属性可能会受到影响,这样渲染树就会发生改变,也就会重新构造renderTree渲染树。

重点 : 回流一定触发重绘,但重绘不一定会回流**

回流触发的条件

页面布局和元素集合属性改变都会触发回流:

  • 页面初始渲染
  • 添加/删除可见dom元素
  • 改变元素位置
  • 改变元素内容(文本或者图片等)
  • 改变元素尺寸(宽高、内外边距,边框等)
  • 改变字体大小
  • 改变窗口尺寸(resize)
  • 激活css伪类
  • 设置style属性值
  • 查询某些属性或调用某些方法

    会触发回流的属性和方法

  • clientWidth,clientHeight,clientTop,clientLeft

  • offsetWidth,offsetHeight,offsetTop,offsetLeft
  • scrollWidth,scrollHeight,scrollTop,scrollLeft
  • scrollIntoView(),scrollIntoViewIfNeeded()
  • getComputedStyle() (ie使用的是currentStyle)
  • getBoundingClientRect()t
  • scrollTo()
  • width/height/padding/border/margin
  • font/line-height/font-weight
  • position/display/float/clearidt

h,clienimage.pngtH

如何解决回流

css

  • 避免使用table布局
  • 尽可能在dom树的最末端改变class
  • 避免设置多层内联样式
  • 将动画效果应用到position属性为absolute或者fixed的元素上
  • 避免使用css表达式(cala())

jajavascriipt

  • 避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并于一次更改class属性
  • 避免频繁操作dom,创建一个documentFragment,在它上面应用所有的dom操作,最后再把它添加到文档中
  • 可以先为元素display:none,操作结束后再把它显示出来,因为在display属性为none的元素上进行的dom操作不会引发回流和重绘
  • 对具有复杂动画的元素使用绝对定位,使他脱离文档流,否则会引起父元素以及后续元素频繁回流,基本原则:把动画元素用position:absolute踢出文档流,单独渲染本部分。

    部分代码实现

    浏览器优化:渲染队列

    1. div.style.left='10px';
    2. div.style.right='15px';
    3. //console.log(div.offsetTop);
    4. div.style.top='15px';
    5. div.style.bottom='8px';
    例子中看着是四次,但是实际上只有1次重排,因为浏览器有渲染队列机制,当我改变了元素的一个样式会导致浏览器发生重排或重绘时,它会进入一个渲染队列,然后浏览器继续往下看,如果下面还有样式修改,那么同样入队,直到下面没有样式修改,浏览器会按照渲染队列批量执行来优化重排过程,一并修改样式,这样就把本该4次的重排优化为1次,但是如果像例子中输出offsetTop属性,就会是两次重排,因为offset|client|scroll系列会强制刷新队列要求样式修改任务立即执行(这一过程强制浏览器将本来在上述渲染流程中才执行的layout过程前提至js执行过程中,强制回流),

    分离读写

    1. div.style.top='1px';
    2. div.style.bottom='8px';
    3. console.log(div.offsetTop);
    4. console.log(div.offsetBottom);
    5. //重排一次

    样式集中变化(批量处理)

    ```javascript div.style.left = ‘5px’; div.style.top = ‘12px’; div.style.width = ‘20px’; div.style.height = ‘20px’;

div.style.cssText = ‘left:10px;top:10px;width:20px;height:20px;’;//只触发一次

  1. <a name="mJCvK"></a>
  2. #### 缓存布局信息
  3. ```javascript
  4. var curLeft = div.offsetLeft;
  5. var curTop = div.offsetTop;
  6. div.style.left = curLeft + 1 + 'px';
  7. div.style.top = curTop + 1 + 'px';
  8. //元素批量修改,利用文档碎片

元素批量修改

  1. //文档碎片:createDocumentFragment
  2. let frg=document.createDocumentFragment();
  3. for(let i=0;i<5;i++){
  4. let newLi=document.createElement('li');
  5. newLi=document.createElement('li');
  6. newLi.innerHTML=i;
  7. //创建的li放到文档碎片中
  8. frg.appendChild(newLi);
  9. }
  10. //一次性把内容放到容器中,引发一次回流
  11. box.appendChild(frg);
  1. //字符串拼接
  2. let str=``;
  3. for(let i=0;i<5;i++){
  4. str+=`<li>${i}<\li>`
  5. }
  6. box.innerHTML=str;