只有10-20%的最终用户响应时间花在了下载HTML文档上。其余的80-90%时间花在了下载页面中的所有组件上。

规则1、减少HTTP请求
  1. 图片地图:将多个图片合并成一个,而后通过css定位显示不同的位置
  2. CSS Sprites:同上
  3. 内联图片
  4. 合并脚本和样式表
规则2、使用内容发布网络(CDN,Content Delivery Network)
规则3、添加Expires头
  1. Expires头:在这一日期/时间之后,响应将被认为是无效的
  2. Max-Age: 设置相对有效时间Cache-Control:max-age=100
  3. 空缓存VS完整缓存:尽可能将页面内容放入大缓存中
  4. 不仅仅是图片:图片应该使用缓存,但这一最佳实践不应该仅限于图片
  5. 修订文件名:为能够获取最新的文件,最有效的解决方案是修改其所有链接,这样,全新的请求将从原始服务器下载最新的内容。
规则4、压缩组件
  1. gzip:Accept-Encoding:gzip,deflate。gzip是目前最流行和最有效的压缩方法,是最理想的压缩方法
  2. 压缩内容:压缩脚本和样式表是非常值得的,同时还有XML和JSON在内的文本。图片和PDF不应该压缩,因为它们本来就已经被压缩了。
  3. 节省率:压缩通常能将响应的数据量减少将近70%
  4. gzip配置:不同的web服务器有不同的gzip配置方式,但大多支持gzip
  5. 代理缓存:Web服务器基于Accept-Encoding来检测是否对响应进行压缩。不管是否压缩过,浏览器都会基于响应中的其他HTTP头如Expires和Cache-Control来缓存响应。由于压缩的决定是基于Accept-Encoding请求头的,因此需要在服务器的Vary响应头中包含Accept-Encoding。
  6. 边缘情形:服务器和客户端的压缩对等性看似简单,但必须正确才行。无论是客户端还是服务器发生错误(发送压缩内容到不支持它的客户端、忘记将压缩内容声明为已经进行了gzip编码等),页面都会被破坏。错误并不会经常发生,但它们是必须考虑的边缘情形(Edge Case)。这种情况虽然可以通过浏览器白名单方式解决,但设置浏览器白名单的指令过于复杂,无法使用HTTP头进行编码。最佳做法是将User-Agent作为代理的另外一种判断标准添加到Vary头中Vary:Accept-Encoding,User-Agent
规则5、将样式表放在顶部

规则5对于加载页面所需的实际时间没有太多影响,它影响更多的是浏览器对这些组件顺序的反应。为避免当样式变化时重绘页面中的元素,浏览器会等待位于底部的样式表加载完成后才会呈现,这时浏览器会延迟任何可视化组件。实际上,用户感觉缓慢的页面反而是可视化组建加载得更快的页面。使用LINK标签将样式表放在文档的HEAD中可以解决该问题。

在使用样式表时,页面逐步呈现会被阻止,直到所有的样式表下载完成。将样式表移到文档head中,这样就能首先下载它们而不会阻止页面呈现。

规则6、将脚本放在底部
  1. 并行下载 对响应时间影响最大的是页面中组件的数量,如果一个Web页面平均地将其组件分别放在两个主机名下,整体响应时间将可以减少大约一半。但并行下载数量并不是越多越快,因为增加并行下载数量是有开销的,其优劣取决于带宽和cpu速度。
  2. 脚本阻塞下载 并行下载组件的优点是很明显的,然而,在下载脚本时并行下载实际上被禁用的。即使使用了不同的主机名,浏览器也不会启动其他的下载。其中一个原因是,脚本可能使用document.write来修改页面内容,因此浏览器会等待,已确保页面能够恰当地布局。另一个原因是为了保证脚本能够按照正确的顺序执行。

在使用脚本时,对于所有位于脚本以下的内容,逐步呈现都被阻塞了。将脚本放在页面越靠下的地方,意味着越多的内容能逐步地呈现。

规则7、避免css表达式
规则8、使用外部JavaScript和Css
  1. 纯碎而言,内联快一些
  2. 页面查看 每个用户产生的页面查看越少,内联JavaScript和Css的论据越强势。另一方面,如果普通用户能够产生很多的页面查看,浏览器很可能将(具有长久的Expires头的)外部文件放在其缓存中。
  3. 组件重用  如果你的网站中的每一个页面都使用了相同的JavaScript和Css,使用外部文件可以提高这些组件的重用率。在这种情况下使用外部文件更加具有优势,因为当用户在页面间浏览时,JavaScript和Css组件已经位于浏览器的缓存中了。
  4. 动态内联  如果主页服务器知道一个组件是否在浏览器的缓存中,它可以在内联和使用外部文件之间做出最佳选择。尽管服务器不能查看浏览器缓存中有些什么,但可以用cookies做指示器。如果cookie不存在,就内联了JavaScript和Css。如果cookie出现了,则有可能外部组件位于浏览器的缓存中,并使用了外部文件。
规则9、减少DNS查找

Internet是通过IP地址来查找服务器的。由于IP地址很难记忆,通常使用包含主机名的URL来取代它,但当浏览器发送其请求时,IP地址仍然是必需的。这就是Domain Name System(DNS) 所处的角色。DNS也有开销,通常浏览器查找一个给定的主机名的IP地址要花费20-120毫秒。响应时间依赖于DNS解析器(通常由你的ISP提供)、它所承担的请求压力、你与它之间的距离和你的带宽速度。

  1. DNS缓存  DNS查找可以被缓存起来提高性能。这种缓存可以发生在由你的ISP或局域网中的一台特殊的缓存服务器上,但这里探讨的是发生在独立用户的计算机上的DNS缓存。在用户请求了一个主机名之后,DNS信息会留在操作系统的DNS缓存中,之后对于该主机名的请求将无需进行过多的DNS查找,至少短时间内不需要。·
  2. 影响DNS缓存的因素 首先,服务器可以表明记录可以被缓存多久。查找返回的DNS记录包含了一个存活时间(Time-to-live,TTL)值。该值告诉客户端可以对该记录缓存多久,尽管操作系统缓存会考虑TTL值,但浏览器通常忽略该值,并设置它自己的时间限制。另外浏览器对缓存的DNS记录的数量也有限制,TTL设置值通常是1天。
  3. 减少DNS查找  当客户端的DNS缓存为空(浏览器和操作系统都是)时,DNS查找的数量与Web页面中唯一主机名的数量相等。这包括页面URL、图片、脚本文件、样式表、Flash对象等的主机名。减少唯一主机名的数量就可以就可以减少DNS查找的数量。
  4. 通过使用Keep-Alive和较少的域名来减少DNS查找
规则10、精简JavaScript

JavaScript作为一门解释型语言,是构建Web页面的首选。当以快速原型为基准开发用户界面时,解释语言要优于其他语言。

  1. 精简 是从代码中移除不必要的字符以减少其大小,进而改善加载时间的实践。在代码被精简后,所有的注释以及不必要的空白字符(空格、换行和制表符)都将被移除。对于JavaScript而言,这可以改善响应时间效率,因为需要下载的文件大小减少了。精简JavaScript最流行的工具是JSMin。
  2. 混淆  是可以应用在源代码上的另外一种优化方式。和精简一样,它也会移除注释和空白,同时它还会改写代码。作为改写的一部分,函数和变量的名字将被转换为更短的字符串,这时的代码更加精炼。但是会带来三个弊端:可能引入错误、增加调试难度、需要对JavaScript关键字标记
  3. 内联脚本  内联的JavaScript块也应该精简
规则11、避免重定向

重定向用于将用户从一个URL重新路由到另一个URL,种类有很多,常用的是301和302。它是损伤性能的,可以采用Alias、mod_rewirte、DirectorySlash和直接连接代码来避免重定向。

规则12、移除重复脚本
  1. 重复脚本--确有其事 开发一个网站需要极大数量的资源,除了核心团队要构建网站外,其他团队也会向页面贡献HTML代码。由于来自不同团队的很多人都要向页面中添加HTML,很容易想到相同的脚本可能会被添加多次
  2. 重复脚本伤害性能 引起不必要的HTTP请求和执行JavaScript所消耗的时间
规则13、配置ETag

实体标签(Entity Tag,ETag)是Web服务器和浏览器用于确认缓存组件的有效性的一种机制。减少呈现页面时所必需的HTTP请求的数量是加速用户体验的最佳方式。可以通过最大化浏览器缓存组件的能力来实现这一目标,但当网站被宿主在多于一台服务器上时,ETag头可能会阻碍缓存。

ETag带来的问题 ETag的问题在于,通常使用组件的某些属性来构造它,这些属性对于特定的、寄宿了网站的服务器来说是唯一的。当浏览器从一台服务器上获取了原始组件,之后又向另外一台不同的服务器发起条件GET请求时,ETag是不会匹配的----而对于使用服务器集群来处理请求的网站来说,这是很常见的一种情况。默认情况下,对于拥有多台服务器的网站,Apache和IIS向ETag中嵌入的数据都会大大地降低有效性验证的成功率。

解决该问题的两种方式:选择ETag的配置方式或者直接移除ETag

规则14、使Ajax可缓存

Ajax表示异步JavaScript和XML(Asynchronous JavaScript and XML),尽管今天除了XML有很多其他选择,最著名的是JSON。Ajax的目的是为了突破Web本质的开始--停止交互方式。向用户显示一个白屏然后重绘整个页面不是一种后的用户体验。而Ajax在UI和Web服务器之间插入了一层。这个Ajax层位于客户端,与Web服务器进行交互以获取请求的信息,并与表现层交互,仅更新哪些必要的组件。它将Web体验从“浏览页面”转变为“与应用程序进行交互”。

Ajax的一个明显优点是向用户提供了及时反馈,因为它异步地从后端Web服务器请求信息。但Ajax并不保证用户就不会一边玩弄自己的手指一边等着“异步JavaScript和XML”返回响应,记住“异步”并没有暗示“即时”,这一点很重要。用户是否需要等待的关键因素在于Ajax请求是被动的还是主动的。被动请求是为了将来使用而预先发起的。主动请求是基于用户当前的操作而发起的。

改善Ajax请求的最重要的方式就是使响应可缓存,前面第4、9、10、11、13原则也适用于此。

确保Ajax请求遵守性能指导,尤其应具有长久的Expires头。

 
 

<读书笔记>《高性能网站建设指南:前端工程师技能精髓》的更多相关文章

  1. 简单物联网:外网访问内网路由器下树莓派Flask服务器

    最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...

  2. 利用ssh反向代理以及autossh实现从外网连接内网服务器

    前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...

  3. 外网访问内网Docker容器

    外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...

  4. 外网访问内网SpringBoot

    外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...

  5. 外网访问内网Elasticsearch WEB

    外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...

  6. 怎样从外网访问内网Rails

    外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...

  7. 怎样从外网访问内网Memcached数据库

    外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...

  8. 怎样从外网访问内网CouchDB数据库

    外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...

  9. 怎样从外网访问内网DB2数据库

    外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...

  10. 怎样从外网访问内网OpenLDAP数据库

    外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...

随机推荐

  1. Jenkins构建触发器的区别

    Build periodically:定时进行项目构建或执行(它不care源码是否发生变化),配置如下: 0 2 * * *  (每天2:00 必须build一次源码) 如果是要定时执行脚本,需要选择 ...

  2. Get The Treasury【HDU-3642】【扫描线】

    题目链接 题目给出的是N个体积块,问的是有多少体积重叠了3次及以上? 那么就是怎么处理体积这样子的问题了,看到Z的种类不多的时候,就想着从Z离散化的角度去考虑这个问题了,然后就是怎样子去处理面积了,这 ...

  3. node_exporter + grafana

    监控服务器CPU.内存.磁盘.I/O等信息,首先需要安装node_exporter.node_exporter的作用是用于机器系统数据收集. 下载安装: https://github.com/prom ...

  4. Cocos2d Box2D之碰撞检测

    |   版权声明:本文为博主原创文章,未经博主允许不得转载. 在Box2D中碰撞事件由b2ContactListener类函数实现,b2ContactListener是Box2D提供的抽象类,它的抽象 ...

  5. javaIO流(三)--IO深入操作

    一.字符编码 在计算机的世界中,本质上只认识0,1的字节数据,如果要想描述一些文字的编码就需要对这些二进制的数据进行组合,就需要对二进制的数据进行组合,所以才有了现在可看见的中文显示,但是在进行编码的 ...

  6. scrapy框架--新建调试的main.py文件

    一.原因: 由于pycharm中没有scrapy的一个模板,所有没办法直接在scrapy文件中调试,所有我们需要写一个自己的main.py文件,在文件里面调用命令行,来实现scrapy的一个调试.(在 ...

  7. 什么是Kotlin?Java的替代语言?

    什么是Kotlin Kotlin是一个基于JVM的新的编程语言,2010年由IntelliJ IDEA所在的JetBrains公司开发,自2012年以来一直开源. Kotlin可以编译成Java字节码 ...

  8. Shell脚本中判断输入变量或者参数是否为空的方法

    shell判断一个变量是否为空方法总结 https://www.jb51.net/article/154835.htm 1.判断变量 复制代码代码如下: read -p "input a w ...

  9. 【目录】mysql 架构篇系列

    随笔分类 - mysql 架构篇系列 mysql 架构篇系列 4 复制架构一主一从搭建(半同步复制) 摘要: 一.概述 在mysql 5.5之前,mysql 的复制是异步操作,主库和从库的数据之间存在 ...

  10. WPFの多屏幕问题

    public MainWindow(string sysName, int timeState) { InitializeComponent(); //查找当前屏幕数量 ) { Dispatcher. ...