PageSpeed 学习 [1]

04 Dec 2017

Course

Rails 网站效能

前端效能:浏览器运行(HTML/CSS/Javascript)代码渲染出换面的时间,这个时间叫Page Load Time

2E178572-2A16-4301-90E8-218FF30B3207

(注意右上角选择No throttling, 然后在右下角看Load Time)

http archive 有记录各种数据,比如加载一个页面平均需要的request

后端效能优化都是毫秒级别的,而前端效能优化都是几秒级别的。 所以相对来说,前端效能显的更重要一些。

前端看中 Page Load Time 而不是 单一的Request时间

Google提供的PageSpeed Insights可用来进行线上分析

这个是PageSpeed Insights的Rules

Chrome插件Lighthouse一样可以用来作测评

注意Chrome develop tool是提供了 模仿手机上网低网速的开关的。 9B56AA66-830F-42FA-95AF-B1769A8476AF

优化方向

  1. 减少Requests的请求数量
  2. 减少这些档案的大小

在部署到Producation环境时,Asset Pipeline会执行rake assets:precompile 来将css和js进行合并压缩。 变成如下的样子: 7C6B2662-AC6C-4CA4-B0FA-37618E6CEC90

也就是说 所有css压缩成一个 所有js压缩成一个

css的压缩是通过 sass-rails gem js的压缩是通过 uglifier gem

在本地跑production

# config/database.yml
development:
  <<: *default
  database: db/development.sqlite3

production:
  <<: *default
-   database: db/production.sqlite3
+   database: db/development.sqlite3

bundle exec rake assets:precompile 在本机执行Assets Pipleline编译

暂时修改config/environments/production.rb中打开public_file_server 这会允许Rails服务器可以回传静态档案 (在正式服务器上,静态档案会由Ngix处理,所以默认是关闭)

# config/environments/production.rb
- config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
+ config.public_file_server.enabled = true

rails s -e production

编译出来的assets档案,放在public/assets下,实验完了以后需要砍掉 砍掉方式:

  • bundle exec rake assets:clobber
  • 或者rm -rf public/assets

HTTP 优化

HTTP压缩 使用gzip压缩(因为服务器和浏览器都支持这种压缩协议)。 在用Nginx的时候就会去配置

gzip on;
gzip_disable "msie6";

gzip_comp_level    5;
gzip_min_length    256;
gzip_proxied       any;
gzip_vary          on;
gzip_types application/atom+xml application/javascript application/x-javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/xml text/plain text/javascript text/x-component;

这样Nginx会对纯文字的档案进行压缩

我们可以在response header中找到gzip的踪迹 16A01924-6DCD-4329-9334-760AC571012F 3300D61F-4BD8-4C12-8A52-98C74CB359ED

可以看出,压缩前和压缩后的变化还是很大的。

HTTP缓存

Nginx设定

location ~ ^/assets/ {
  expires 1y;
  add_header Cache_Control public;
  add_header ETag "";
  break;
}

这样就会针对/assets/ 目录下的静态档案,在HTTP Response里加入以下Headers

C623D3F4-0FB1-4E99-BF01-DD6E3E1FD1BB

cache-control: public 就是指定这个可以被浏览器缓存 cache-control: max-age=3153600expire 则是高速浏览器可以缓存多久 一般是缓存一年 疑问:如果有这些缓存的文件源代码在服务器上有更新怎么办? 解答:每次服务端有改动,就会执行rake assets:precompile,而执行的时候会利用Rails assets pipleline的digest功能给文档名加上编码。这样发送到前端与之前的就不会重名,有更新的时候,前端会根据这个文档名来找,如果本地有就用本地的,如果没有,就去服务器上请求下载。

8B52998E-1F15-4E05-8F35-25D96AE3E226

这里就可以发现,这些文件都是从本地缓存而来的。

HTTP/2

更快更安全: 每個網站都應該升級到 HTTP/2 | ihower { blogging } 当升级到HTTP/2也会有很大的提升。

没有HTTP/2的时候大家能想到的方案是:

  • 图片合并(小图合并大图,相当于一次传了很多图)
  • js与css合并
  • 把css/js/图片直接用base64编码进html中(不过造成没有了静态资源的快取功能,因为图片使文件变很大)
  • Domain Sharding 来突破一个domain只能开6个网络线路的限制。

http/2做了什么

  • Single TCP connection 就可以连接服务器。不用多条线路保持连线
  • Multiplexing 单一线路上,可以传输多个HTTP Request/Response
  • Prioritizaiton
  • Header压缩,(很多时候,header大部分都相同)
  • Binary 用二进制来封装结构设计(解析加快)
  • 服务器可以选择主动推送 文档

Critical Rendering Path

关键渲染路径⭐️⭐️ author: LLya Grigorik 还有本书也是相关的High Performance Brower Networking

Optimizing the critical rendering path refers to prioritizing the display of content that relates to current user action.

Optimizing for performance is all about understanding what happens in these intermediate steps between receiving the HTML, CSS, and JavaScript bytes and the required processing to turn them into rendered pixels - that’s the critical rendering path.

27A54F83-AEF3-4848-9CDD-4DF8043619D

优化就是先加载和渲染当前最需要的内容。

测量performance的工具就是 Google development tool中的Performance工具

浏览器渲染画面(Browser Rendering)过程

  • 浏览器下载HTML
  • 浏览器针对HTML上的外部资源(CSS/JavaScript/图片)发送HTTP Requests去获取,在HTTP 1.1时代只能同时抓取六个资源、在HTTP/2之后则可以同时平行抓取。
  • 同一时间浏览器也从HTML源码中,按从上到下顺序开始解析,进行渲染
    • 用HTML建立Document Object Model(DOM)
    • 用CSS建立CSS Object Model(CSSOM),如果CSS还没下载完成,会原地等待
    • 执行JavaScript来操作DOM和CSSOM, 如果JavaScript还没下载完成,原地等待
    • 建立Render Tree
    • 计算每个元素在画面上的位置 Layout
    • 真正开始paint每一个pixels

这整个路径,对于想要进行Render time优化的人来说,就是 Critical Rendering Path

JavaScript 加载优化

4B3F1B64-AE73-448B-98FE-8EFAFD5EBD7A

(绿色:HTML渲染;紫色:js下载;红色;js执行)

我们有三种方法 1.把script从head移到底部去 这样实测的加载速度是最快的,但是不能享受Turbolinks的优势。 (Turbolinks原理就是保留head不懂,用Ajax替换body里的内容)

2.async(异步)

430B105B-A5C5-4E0E-B805-876EC34C92A2

特点:JS下载异步,下载完后,马上执行JS

# app/views/layout/applicaiton.html.erb
-  <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
+  <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload', :async => true %>

3.defer(异步+延迟执行)

A6080180-1F7B-4412-BDCE-9E21F2AE48CB

特点:JS异步下载,但等HTML渲染完后,再执行js

# app/views/layouts/application.html.erb
-  <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
+  <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload', :defer => true %>

三种方法带来的问题: 有关Inline

这样会因为顺序的颠倒,导致一些js代码比如调用jquery,而jquery还没加载,那么就出问题了。 (其实描绘的还是不是很清楚,我表示不是很懂)

1.js放在底部的调整方式

<%= javascript_include_tag "application" %>

<%= yield :handwrite_javascript %>
</body>
</html>

把之前卸载html中的js代码用content_for包裹起来

<%= content_for :handwrite_javascritp do %>
<script>
  $("button.continue").html("Next Step...");
</script>
<% end %>

这样做的主要作用是,让引入的js放到最后再下载,然后自己写的就以content_for的形式放在最最后面,这样自己写的inline js就不会因为一些js framework还没加载,导致执行错误了

2.async调整方式

此时HTML中已经不能有inline形式的js代码了 (因为不知道哪些async的js到底什么时候会被加载) 所以js代码全部都要放在打包后的applicaiton.js中。

把layout中的<body>改为<body id="<%= "#{controller_name}-#{action_name}" %>">

$(document).ready(function(){
  if ( $( $("#events-edit").length > 0 ) ) {
    $("#event_category_id").select2( { theme: "bootstrap" } );
  }
})

这样每个页面的body都有独有的id,写自己手写js的是欧,就可以站在跟高一层(所有的页面上面)来选择你的js要在哪个特定的页面来运行。

3.defer的调整方式

# app/views/admin/events/_form.html.erb
<script>
  window.addEventListener('DOMContentLoaded', function() {
    $("#event_category_id").select2( { theme: "bootstrap" } );
  })
</script>

原理:把自己写的js代码,延后到DOMContentLoaded事件之后才触发

CSS优化

Optimize CSS delivery in Rails app – 愛料理技術部落格⭐️⭐️⭐️ Rails是把所有css都打包为一个applicaiton.css 而我们可以根据这篇博客来,抽出一部分必要的css,先下载来进行加载。

这篇blog也把优化工具指向了Google的PageSpeed Insights Google官方的优化CSS建议Opimize CSS Delivery CSS太大带来的问题Google也有解释:Render Blocking CSS

ihower推荐两个指南: Measure Performance with the RAIL Model (效能指南) PageSpeed Insights Rules

工具:Lighthouse 这个你只需要给他一个网址,就可以帮你跑测试,然后给你解决效能的建议和修改方案。 这个工具有三个使用场景:Chrome DevTools, command line, your continuous integration systems

CDN服务

CDN在rails中的配置只需要一句话

# config/envirments/production.rb
config.action_controller.asset_host = "https://cdn.jd.com"

8DB3B286-9220-4BBB-AC0D-A2C2CA754873

Wiki

PageSpeed Insights Rules

PageSpeed Insights Rules

Speed Rules

  • Avoid landing page redirects
  • Enable compression
  • Improve server response time
  • Leverage browser caching
  • Minify resources
  • Optimize images
  • Optimize CSS Delivery
  • Prioritize visible content
  • Remove render-blocking JavaScript
  • Use asynchronous scripts

Usability Rules

  • Avoid plugins
  • Configure the viewport
  • Size content to viewport
  • Size tap targets appropriately
  • Use legible font sizes

Avoid landing page redirects

最好是只用Responsive Web Design (这个需要看完) redirect能少就少,因为redirect会造成额外的一次或者多次http roundtrip Responsive web Design的提出者Ethan Marcotte in A List Apart 他还有本书Responsive web design

Udacity提供的Responsive的课程Udacity - Responsive Web Desing

如果有一定要有rediret比如使用www.example.comm.example.com 那么需要遵从这个文档Separate URLs

Avoid Plugins

Avoid Plugins Flash,Silverlight Java都属于是过去的浏览器插件 现在由于推出H5,audio,video,graphics,presentation,network connection, storage, file access都是以使用native web technologies来做了,所以可以不需要那些并不安全的插件了,而且还影响性能,而且很多手机浏览器是不支持大多数插件的。

Configure the Viewport

Configure the Viewport CSS 淺談 @viewport 與 @media这个blog讲的蛮好的,而且还有ihower,高见龙等不少人关注他。 快捷提示:别忘记Viewport Meta标签

推荐设置 <meta name=viewport content="width=device-width, initial-scale=1">

Enable Compression

Enalbe Compression gzip都是现代浏览器默认使用的压缩协议,如果双方都支持并使用这种压缩协议,那么能减少90%的传输时间,这个主要是针对纯文本的压缩。 这里是多个服务器的gizp配置server-config 其中nginx的配置文件在这里nginx.conf,看了这个文件才发现,ihower的配置是参照的这里,而且巨多人贡献出来的结果,我挑了一些我感觉跟gzip有关的配置出来,而且都有解释

  # Enable gzip compression.
  # Default: off
  gzip on;

  # Compression level (1-9).
  # 5 is a perfect compromise between size and CPU usage, offering about
  # 75% reduction for most ASCII files (almost identical to level 9).
  # Default: 1
  gzip_comp_level    5;

  # Don't compress anything that's already small and unlikely to shrink much
  # if at all (the default is 20 bytes, which is bad as that usually leads to
  # larger files after gzipping).
  # Default: 20
  gzip_min_length    256;

  # Compress data even for clients that are connecting to us via proxies,
  # identified by the "Via" header (required for CloudFront).
  # Default: off
  gzip_proxied       any;

  # Tell proxies to cache both the gzipped and regular version of a resource
  # whenever the client's Accept-Encoding capabilities header varies;
  # Avoids the issue where a non-gzip capable client (which is extremely rare
  # today) would display gibberish if their proxy gave them the gzipped version.
  # Default: off
  gzip_vary          on;

  # Compress all output labeled with one of the following MIME-types.
  # text/html is always compressed by gzip module.
  # Default: text/html
  gzip_types
    application/atom+xml
    application/javascript
    application/json
    application/ld+json
    application/manifest+json
    application/rss+xml
    application/vnd.geo+json
    application/vnd.ms-fontobject
    application/x-font-ttf
    application/x-web-app-manifest+json
    application/xhtml+xml
    application/xml
    font/opentype
    image/bmp
    image/svg+xml
    image/x-icon
    text/cache-manifest
    text/css
    text/plain
    text/vcard
    text/vnd.rim.location.xloc
    text/vtt
    text/x-component
    text/x-cross-domain-policy;

Improve Server Response Time

Improve Server Response Time 超过200ms的 response time就会认为有优化的需求

属于是服务器后端优化

Leverage Browser Caching

Leverage Browser Caching

response里一定要说明的关于cached的事情

  • by whom
  • for how long
  • if applicable
  • how it can be efficiently revalidated when the caching policy expires

更明确的说就是需要至少有两个东西要指明

  • Cache-Control 指明是否可以存储,可以存多久 Cache-Control
  • Etag 是一个 revalidation token,用来指明这次的response是否有了新的变化

HTTP Caching

6F0264B0-1C29-4137-9FD1-744FF1FFE655

可以缓存120秒 而Etag就是在这个120秒内容用来传给后台比对是否有新的内容需要产生。

ECA9A406-5D2A-48A8-89AD-BCD46F4BFCEB

浏览器(client)发送第一次回传的Etag token ,形式是 If-None-Match: x234dff 网站后台(Server),会重新针对请求的内容与上次同样算法计算一个token与传过来的这个x234dff进行比对,如果一样的话,就返回: 304 Not Modified Cache-Control: max-age=120 Etag: “x234dff”

Cache-Control

no-cache / no-store

public就是谁都可以患处,这种用处不多 private就是CDN不能患处,但是浏览器可以缓存

max-age 就是说可以存多久

EB03CCB7-4621-46E1-A756-958A9EB4FD3

Invalidating and updating cached response

Caching checklist

  • Use consistent URLs
  • Ensure that the server provides a validation token(ETag)
  • Identify which resources can be cached by intermediaries
  • Determine the optimal cache lifetime for each resource
  • Determine the best cache hierarchy for your site
  • minimize churn

这篇HTTP Caching很重要,做Caching就要参考它

Minify Resources(HTML, CSS and JavaScript)

Minify Resources(HTML, CSS, and JavaScript)

preprocessing & context-specific optimizations

还可以用PageSpeed Module来在Apache/Nginx上作自动化优化

Optimize Images

Optimize Images 可以用ImageMagic对图片作二进制转换 Gif与PNG都属于是lossless format 无损格式

另一种方案用矢量图,不过应用场景比较窄

Image Optimization 8A767F0A-E350-4612-B0AC-7D8001212DFE

Optimize CSS Delivery

Optimize CSS Delivery

Render-treee Construction, Layout, and Paint

90A142A8-C3F4-4AB3-AFB8-EB5C0B75B282

Render Steps

  1. Process HTML markup and build the DOM tree.
  2. Process CSS markup and build the CSSOM tree.
  3. Combine the DOM and CSSOM into a render tree.
  4. Run layout on the render tree to compute geometry of each node.
  5. Paint the individual nodes to the screen.

Render Blocking CSS

可利用media query来设定css的使用场景,来在特定情况下渲染特定的css

<link href="style.css"    rel="stylesheet">
<link href="style.css"    rel="stylesheet" media="all">
<link href="portrait.css" rel="stylesheet" media="orientation:portrait">
<link href="print.css"    rel="stylesheet" media="print">

等等一些没看了…

Reduce the size of the above-the-fold content

Reduce the size of the above-the-fold content

首屏内容所需要的请求尽量少 加载顺序为先加载主要内容 缩减资源大小 考虑使用css而不是图片 启用压缩功能

Remove Render-Blocking JavaScript

Remove Render-Blocking JavaScript

  • Inline Js
  • Async <script async src="my.js">
  • Defer

Use Asynchronous Scripts

Use Asynchronous Script 现在有很多script天生就支持async异步,所以能用Asynchronous Scripts就尽量用这种。