• 前端不要性无能


    性能

    性能=习惯+工具

    一、无阻塞脚本

    众所周知,浏览器解析html页面的步骤,简介一下

    • 从head开始,下载外部样式、脚本并逐一执行
    • 完成dom树的构造
    • 请求外部资源,如图片,音频等

    注:指定图片大小,可以避免浏览器自己耗费时间来计算

    回归主题,浏览器一般只能同时下载两个资源,在此过程中(包括执行),页面保持阻塞,也即,即使cou空闲,也不能干别的事情。最终结果就是,页面响应缓慢。

    我们可以做更多的事,如果没有阻塞,如何才能不阻塞?

    • 添加脚本属性<script async|deffer src="">

      • deffer属性指定,这个脚本不会修改dom,可以延迟执行(页面完成解析时执行)。
      • async属性指定脚本将被异步载入,下载完成后立即执行,不会影响页面其余部分的解析。当然如果存在多个这样的文件,它们的执行是无序的。async为html5新增属性。
      • 上述属性,都存在兼容性问题。
    • 使用Ajax,来异步的载入脚本,脚本的执行时机是可控的,而且浏览器兼容性很好。但是有个致命的弱点,存在跨域限制,一棍子打死。

    • 使用Web Works,浏览器会创建一个子进程来处理这个异步任务,不阻塞页面渲染,支持跨域访问。如果你的产品,要支持的浏览器比较高级,可以一用。

    • 有没有一种即兼容、又能跨域,还能无阻塞的方案呢?当然有的。动态脚本

      • 在Js中创建Script标签,并插入文档,不支持这个的,就不能称为浏览器。
      • 对于src属性指定的文件,是没有跨域限制的。不论是script,还是img标签,这也是jsonp的实现跨域的基础。
      • 对于动态插入的标签,下载和执行都是异步的,即不阻塞页面解析。
      • 下载完成后,代码立即执行,如果是代码无依赖的自执行,是没有问题的。如果作为其它脚本的一部分,则必须要确保其余脚本必须在其之后执行。状态监听,可以通过script.onload来监听文件是否下载并执行完成。IE则需要通过readyState来检查脚本状态。

    二、计时器与长脚本

    单个脚本的执行时间,不应该超过100ms

    计时器,是javascript中非常重要的对象,尽管它并不精确。

    • 100ms,如果一个脚本的执行时间,超过100ms,用户会认为失去对界面的控制。我们需要控制长脚本的运行时间。
    • 25ms,处于对计时器稳定的考虑,计时器的间隔时间,应当>=25ms.同时25ms也是更新UI的必要时间。
    • UI线程·,浏览器只有一个UI线程,用于JS执行和页面渲染。Ta使用队列来管理UI任务,如果当前有JS在执行,或者UI更新,那么新增的任务被放入队列。但是,当JS处于执行状态,那么,UI更新将不被添加到执行队列。比如点击按钮,虽然点击事件会被添加到队列,但是,按钮的状态更改会被忽略。
    • 如果一个脚本需要运行几秒钟,由于单线程的缘故,对用户来说肯定是不可接受的,怎么办?我们可以使用计时器,来分隔任务.创建定时器,会重置浏览器限制,和调用栈。在等待的过程中,UI线程可以利用这个时间片,继续处理其它任务。

    一个页面最好只有一个计时器,以避免多个计时器争夺时间片,造成阻塞。同时低频计时器(>=1s)优于高频计时器(100-200ms).

    三、浏览器的重绘与重排

    重排一定重绘,重绘不一定重排。

    • 浏览器为每个页面建立两颗树,dom树渲染树
    • 重排,dom元素的几何属性发生改变,引起渲染树相关部分的失效和重排。
    • 重绘,将元素更改的属性,绘制到屏幕上。
    • 为了最小化重排,我们需要使用一些方法来使元素脱离文档。在这里对元素应用多重修改,而不会导致多次重排。(仅在带出元素和带入元素两步,引起重排)
      • 将元素设置为display:none,这样的元素不会出现在渲染树中。
      • 使用document fragment,文档片段,在dom树外,修改元素。
      • 使用cloneNode来创建一个不在dom树总的节点。
      • 使用绝对定位,使元素脱离文档流。避免引起大面积重排。
    • 应当批量的修改属性,而非频繁的逐一修改。
    • 浏览器,默认会使用队列来缓存修改信息,但是如果当你使用如offsetTop,clientTop,scrollTop等属性时,会强制刷新队列,已获得最新的布局信息。

    参考书籍,《高性能Javascript》 Nicbloas

  • 相关阅读:
    RabbitMQ入门(二)工作队列
    RabbitMQ入门之Hello World
    利用JMeter测试Tornado的多线程
    使用SQLAlchemy操作MySQL
    计算斐波那契数列的性能对比:Python,Java,Go
    PyCharm使用之配置SSH Interpreter
    Android数据绑定技术一,企业级开发
    Retrofit网络请求库应用02——json解析
    Servlet与Jsp的结合使用实现信息管理系统二
    Retrofit网络请求库应用01
  • 原文地址:https://www.cnblogs.com/ywb15ba/p/speed2.html
Copyright © 2020-2023  润新知