zoukankan      html  css  js  c++  java
  • 常见web性能优化

    为什么要有性能优化?回忆一下,当你打开一个网页时,你能忍受的打开速度是几秒?超过5秒你可能会立即走人。。。网站的加载速度严重影响了用户体验,也决定了这个网站的生死存亡。

    减少HTTP请求

      为什么?性能黄金法则,在HTTP请求的过程中,只有 10%~20% 的最终用户时间花在了下载 HTML 文档上。其余 80%~90% 的时间花在了下载页面中的所有组件上进行的HTTP请求上;

      改善响应时间最简单的途径就是减少HTTP请求的数量; 

      每下载一个图片、js文件、css文件等等都是一次HTTP请求,所以要尽可能的少下载静态资源;

      使用CSS雪碧图,之前写过一篇文章 

      图片地图

        我们可以通过使用多个分开的图片,然后每个图片都对应一个超链接,当然这也会产生很多HTTP请求,我们目标是减少HTTP请求;   

        图片地图允许你在一个图片上关联多个 URL。目标 URL 的选择取决于用户单击了图片上的那个位置;

        将多个图片合并成一个图片(即将多个HTTP请求减少为一个HTTP请求),然后以位置信息定位超链接;

        具体用法,请移步到 https://www.w3school.com.cn/tags/att_area_coords.asp ;

      尽量合并、压缩CSS、JS文件,或者直接写在页面上

    使用CDN加速

      通俗的说,服务器离用户更近,HTTP 请求的响应时间将缩短;

      CDN(内容发布网络)是一组分布在多个不同地理位置的web服务器,用于更加有效地向用户发布内容;

      借张图说明一下:

      

    利用缓存

      CDN缓存

      DNS缓存

        DNS是“域名系统”的缩写,它的工作是将域名和主机名转化为服务器主机的 IP 地址;

        DNS查找流程:浏览器缓存 — 本地hosts文件 — 本地DNS解析器缓存 — 本地DNS服务器 — 本地DNS服务器设置(是否设置转发器)— 根DNS服务器(返回一个负责该域名服务器的一个IP。本地DNS服务器会根据这个IP继续查找服务器,如果查找到的服务器不能解析此域名,则它会找另一个管理此域名的DNS服务器给本地DNS服务器,重复上面的动作,直到找到域名对应的主机)— 不要晕~

      浏览器缓存之客户端缓存

        无需请求的memory cache,disk cache;

        需要发请求验证的Etag、Last-Modified304;

        H5新增的 localStorage、sessionStorage;

      合理利用以上缓存,可以很大程度上提高前端性能。

    HTML部分

      标签语义化,即用合理、正确的标签来展示内容,比如 h1-h6 定义标题;

      语义化的优点:

        易于用户阅读,样式丢失的时候能让页面呈现清晰的结构;

        有利于SEO,搜索引擎根据标签来确定上下文和各个关键字的权重;

        方便其它设备解析,如盲人阅读器根据语义渲染网页;

        有利于开发和维护,语义化更具可读性,代码更好维护,与CSS关系更和谐;

      HTML很容易被网络爬虫识别,因此搜索引擎可以根据网站的内容在一定程度上实时更新。在写HTML的时候,你应该尽量让它简洁而有效。举个例子:你在写一个网站,这个网站的其中一个模块包括了各个高校的数据信息,而这些数据信息是实时更新的,你可以利用爬虫去获取这些数据信息,如果各个高校的网站的HTML是非常符合语义化标准的,那么你就可以很顺利的爬到这些数据信息;反之,会增加你的爬虫代码的难度

    CSS部分

       将CSS放在HTML的上面部分,这个策略不能提高网站的加载速度,但它不会让访问者长时间看着空白屏幕或者无格式的文本(FOUT)等待。如果网页大部分可见元素已经加载出来了,访问者才更有可能等待加载整个页面,从而带来对前端的优化效果。这就是知觉性能。

      使用 link 而不是@import

        加载页面时,link标签引入的CSS被同时加载;@import引入的CSS将在页面加载完毕后被加载,也就是说,@import会组织浏览器的并行下载;

        link是HTML的元素,不存在兼容性问题;@import只有IE5+才能识别;

        有关link和@import的区别还有很多,推荐一篇文章 https://www.cnblogs.com/my--sunshine/p/6872224.html

        总之,link标签才是最好的选择,它也能提高网站的前端性能。

      合并CSS代码,比如用 margin 来代替 margin-top、margin-bottom、margin-left、margin-right;

      减少重排,重排会导致浏览器重新计算整个文档,重新构建渲染树,这一过程会降低浏览器的渲染速度。我们应该避免发生重排,下面是触发重排的例子

        改变 font-size 和 font-family;

        改变元素的内外边距;

        通过JS改变CSS类;

        通过JS获取DOM元素的位置相关属性(如width、height、left等);

        CSS伪类激活;

        滚动滚动条或者改变窗口大小;

      减少重绘,当元素的外观(如color、background、visibility等属性)发生改变时,会触发重绘。在网站的使用过程中,重绘是无法避免的。不过,浏览器对此做了优化,它会将多次的重排、重绘操作合并为一次执行。不过我们仍需要避免不必要的重绘,如页面滚动时触发的hover事件,可以在滚动的时候禁用 hover 事件,这样页面在滚动时会更加流畅;

      减少使用昂贵的属性,在浏览器绘制屏幕时,所有需要浏览器进行操作或计算的属性相对而言都需要花费更大的代价。如 box-shadow、border-radius、filter、opacity、:nth-child等;

      合并、压缩CSS文件

    JS部分

       注意作用域,避免全局查找,访问全局变量比访问局部变量慢,是因为需要遍历作用域链,查找作用域链需要额外的时间。所以在一个函数中,将访问多次的全局对象或者域外变量存储为局部变量来使用。如某个方法需引用全局变量的值,则在该方法所在的对象的作用域中定义一个局部变量等于全局变量的值。避免不必要的属性查找,将属性设置为全局变量。

      优化循环,当 if-else 较多时,建议使用 switch 语句。当分支较多时,用 switch 的效率是很高的,因为 switch 是随机访问的,就是确定了值之后直接跳转到那个特定的分支,而 if-else 是遍历所有可能值,直到找到合适的分支;

        当循环的数量不多时,展开循环;

      最小化语句数,声明多个变量时,可以使用一个 var 关键字来声明,变量之间用逗号表示;

        使用数组或对象字面量来新建数组或对象,如 var arr = [1,2,3] ;var obj = {a:1,b:2};

      JS的执行尽量脱离DOM树,限制DOM操作的次数优化DOM交互,在《JavaScript高级程序设计》一书有这样一段话:在更新少量节点的时候可以直接向 document.body 节点中添加,但是要向 document 中添加大量数据时,如果直接添加这些新节点,这个过程非常缓慢,因为每添加一个节点都会调用父节点的 appendChild() 方法,为了解决这个问题,可以创建一个文档碎片,把所有新节点附加其上,然后把文档碎片一次性添加到 document 中。

      假如想创建十个段落,常规方式如下:

    for(let i = 0;i < 10;i++){ 
    
      let p = document.createElement("p");
      let txt = document.createTextNode("段落"+i);
      p.appendChild(txt);
      document.body.appendChild(p);    
            
    }

       上段代码调用了10次 document.body.appendChild(),每次都要产生一次页面渲染。这时候可以用文档碎片createDocumentFragment(),

    let fra = document.createDocumentFragment();
    
    for(let i = 0;i < 10;i++){
    
      let p = document.createElement("p");
      let txt = document.createTextNode("段落"+i);
      p.appendChild(txt);
      fra.appendChild(p);        
    
    }
    
    document.body.appendChild(fra);

      上段代码中,每个新的 <p> 元素都被添加到文档碎片中,然后这个碎片被作为参数传递给 appendChild()。fra.appendChild() 实际上并不是把文档碎片加到body中,仅仅是追加碎片中的子节点。document.body.appendChild() 一次代替了10次,也就是说,只产生了一次页面渲染,可以看到明显的性能提升。

      使用事件代理,页面上的事件处理程序的数量和页面响应用户交互的速度之间有个负相关。所以为了减少事件处理程序,尽量使用事件委托技术。

      提高代码的可阅读性,比如正确标记变量,封装某个重复的行为,合理的注释等。

      使用cssText、className一次性改变属性;

      JS定义行为,html定义内容,CSS定义外观;

     持续完善中,若有错误,欢迎指出!

    参考链接

      http://www.ruanyifeng.com/blog/2015/09/web-page-performance-in-depth.html

      https://blog.csdn.net/qq_21891743/article/details/79642605

      https://blog.csdn.net/bluedandelion/article/details/80895021

      https://www.jianshu.com/p/b2c0f32d3dd7

  • 相关阅读:
    【BZOJ 4581】【Usaco2016 Open】Field Reduction
    【BZOJ 4582】【Usaco2016 Open】Diamond Collector
    【BZOJ 4580】【Usaco2016 Open】248
    【BZOJ 3754】Tree之最小方差树
    【51Nod 1501】【算法马拉松 19D】石头剪刀布威力加强版
    【51Nod 1622】【算法马拉松 19C】集合对
    【51Nod 1616】【算法马拉松 19B】最小集合
    【51Nod 1674】【算法马拉松 19A】区间的价值 V2
    【BZOJ 2541】【Vijos 1366】【CTSC 2000】冰原探险
    【BZOJ 1065】【Vijos 1826】【NOI 2008】奥运物流
  • 原文地址:https://www.cnblogs.com/baby-zuji/p/11461986.html
Copyright © 2011-2022 走看看