Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

前端性能优化方案 #6

Open
peachlemon opened this issue Dec 11, 2015 · 2 comments
Open

前端性能优化方案 #6

peachlemon opened this issue Dec 11, 2015 · 2 comments

Comments

@peachlemon
Copy link
Owner

前端性能优化方案介绍


性能真的很重要吗?

大家当然知道它很重要。所以为什么我们还要做出速度很慢的网站,给用户一个糟糕的体验呢?


让我看一个场景

  • 案列(基于Webpagetest)
  • 思考 ???

怎样的规则才能给用户良好的体验呢

  • 当用户能够以2秒以内得到相应时,会感到系统的相应很快;
  • 当用户在2-5秒之间内得到相应,会感觉系统的相应速度还可以;
  • 当用户在5-8秒内得到相应时,会感觉系统的相应速度很慢,但是还可以接受;
  • 当用户在超过8秒后仍然无法得到相应时,会感到系统糟透了,或者认为系统已经失去响应,而选择离开这个Web站点,或者发起第二次请求。

## Let's Go On

Superman

- 页面级优化 - 服务器级优化 - html优化 - CSS优化 - Javascript优化 - 图片优化 - BONUS - ...
## 页面级优化
  • 减少http请求
    • ...
  • 加快DNS解析、减少DNS查询
    • 解析DNS一般耗费20-120ms时间
    • 组件分离部署
    • ...
  • 避免重定向
    • 重定向用于将用户从一个URL重新路由到另一个URL
    • 重定向通过301和302状态代码来完成
  • 设置http缓存
    • 添加Expires或Cache-Control头
  • 延迟加载组件
  • 预加载组件
  • 在多个域中分离组件
    • 分离组件允许你获得最大化并行下载. 确保你使用不超过2-4个域, 因为DNS查找也需要代价
  • 避免使用iframes
    • 即使空白也代价昂贵
    • 阻止页面加载
    • 无语义
  • 避免404错误
    • HTTP请求是昂贵的, 因此生成一个HTTP请求然后得到一个没用的响应是完全没有必要的, 会降低用户体验而得不到任何好处

## 服务器级优化
  • 多域名资源服务器
    • ...
  • 使用CDN
    • ...
  • 添加Expires和Cache-Control头
    • 对于静态组件: 通过设置Expires头为很远的将来,以实施”Never expire”(从来不更新)策略
    • 对于动态组件: 使用一个合适的Cache-Control头来帮助浏览器进行有条件的请求
  • Gzip组件
    • 从HTTP/1.1开始, Web客户端通过在HTTP请求头部的Accept-Encoding头来指示是否支持压缩:Accept-Encoding: gzip, deflate
    • 如果Web服务器在请求中看到这个头, 它就会使用客户端列出的方式之一压缩响应. Web服务器通过响应中的Centent-Encoding头通知web客户端:Content-Encoding: gzip
  • 配置ETags
    • Entity tags(ETags)是一个web服务器和浏览器用来确定浏览器缓存中的组件是否与原始服务器中的相同的一种机制(entity(实体)是组件的另一个说法,如图片,脚本,样式等都是实体)
  • 尽早地刷新缓存
    • ...
  • 对Ajax请求使用Get
    • POST在浏览器中实施分为两步: 首先发送头部, 然后发送数据. 因此在发送一个TCP包时最好使用GET( 除非你有大量的cookies).IE的URL最大长度是2K, 因此如果你发送超过2K的数据你可能不能使用GET.
  • 避免空的图片src地址
    • 发送大量的非预期流量会削弱你的服务器, 特别是页面每天的浏览量成千上万时.
    • 创建一个从来不会被看的页面, 浪费服务器的计算资源
    • 可能破坏用户数据. 如果你通过cookies或其它方式跟踪请求数据, 你就有毁坏数据的可能性. 即使图片请求没有返回一张图片, 所有的头部都被浏览器阅读和接收, 包括所有cookies.当其它的响应被抛弃时, 这种破坏可能已经产生.
  • Cookie的处理
    • 减少cookie尺寸
    • 为页面组件使用无cookie的域名
    • ...

## html优化
  • 避免 内联式/嵌入式 代码
    • 内联式: 在HTML标签的style属性中定义样式,在onclick这样的属性中定义Javascript代码;
    • 嵌入式: 在页面中使用style标签定义样式,使用script标签定义Javascript代码;
    • 引用外部文件: 在style标签中定义href属性引用CSS文件,在script标签中定义src属性引入Javascript文件.
  • 样式在上,脚本在下
    • ...
  • Html Collection
    • ...
  • 优化DOM结构
    • ...
  • 尝试async
    ` <script src="example.js"></script> 使用上面这种方式时,页面会在这个脚本文件被完全下载、解析、执行完后才去渲染之后的HTML,在这之前会一直处于阻塞状态。这就意味着会增加你的页面的加载时间。有时这种行为是我们希望的,而大多数时候则不想要。 <script async src="example.js"></script> `
    使用上面这种方式时,脚本的加载是异步的,不会影响到这之后的页面解析。脚本会在下载完之后立即执行。需要注意的是,如果有多个使用这种方式异步加载的脚本,他们是没有特定的执行顺序的。

## CSS优化
  • CSS Collection
    • 对于使用预处理器例如 Sass, Less, and Stylus, 你可以通过配置缩小编译输出的CSS代码。
    • ...
  • 合并多个css文件
    • 合并你的CSS文件。文件数量的减少就会带来请求数量的减少和更快的页面加载速度。
  • 避免CSS表达式
    • ...
  • 使用 标签而不是 @import
    • 当你在一个外部样式表中使用第二种方式时,浏览器无法通过并行下载的方式下载这个资源,这样就会导致其他资源的下载被阻塞。
  • css选择符的利用

## Javascript优化
  • 异步加载第三方内容

    var script = document.createElement('script'),
        scripts = document.getElementsByTagName('script')[0];
        script.async = true;
        script.src = url;
        scripts.parentNode.insertBefore(script, scripts);
  • Javascript Collection

    • ...
  • 合并多个Javascript文件

    • ...
  • 缓存数组长度
    1、循环无疑是和Javascript性能非常相关的一部分。试着优化循环的逻辑,从而让每次循环更加的高效。
    要做到这一点,方法之一是存储数组的长度,这样的话,在每次循环时都不用重新计算。

    var arr = new Array(1000),
    len, i;
    for (i = 0; i < arr.length; i++) {
      // Bad - size needs to be recalculated 1000 times
    }
    for (i = 0, len = arr.length; i < len; i++) {
      // Good - size is calculated only 1 time and then stored
    }

    2、在迭代document.getElementsByTagName('a')等类似方法生成的HTML节点数组(NodeList)时,缓存数组长度尤为关键。这些集合通常被认为是“活的”,也就是说,当他们所对应的元素发生变化时,他们会被自动更新。

    var links = document.getElementsByTagName('a'),
        len, i;
    for (i = 0; i < links.length; i++) {
      // Bad - each iteration the list of links will be recalculated to see if there was a change
    }
    for (i = 0, len = links.length; i < len; i++) {
      // Good - the list size is first obtained and stored, then compared each iteration
    }
    // Terrible: infinite loop example
    for (i = 0; i < links.length; i++) {
        document.body.appendChild(document.createElement('a'));
      // each iteration the list of links increases, never satisfying the termination condition of the loop
      // this would not happen if the size of the list was stored and used as a condition
    }
  • 避免使用document.write

    • ...
  • 最小化重绘和重画

    • ...
  • 避免不必要的dom操作

    // really bad!
    for (var i = 0; i < 100; i++) {
      document.getElementById("myList").innerHTML += "<span>" + i + "</span>";
    }
    // much better :)
    var myList = "";
    for (var i = 0; i < 100; i++) {
      myList += "<span>" + i + "</span>";
    }
    document.getElementById("myList").innerHTML = myList;
  • 移除重复的脚本

    • ...
  • 开发智能事件处理器

    • 很多时候感觉页面响应很慢, 因为有太多的事件处理器被关联到了DOM树的不同元素上, 这些元素会频繁地执行. 这就是为什么使用event delegation是一个好方法.如果你在一个div中有10个按钮, 只有一个事件处理器关联到div封装器中, 而不是每个按钮有一个处理器. 事件冒泡式地向上传递, 因此你可以捕获这个事件然后找出它起源于哪个按钮.

## 图片优化
  • 使用css sprites

    • 减少了HTTP请求数,避免延迟页面上的其他资源
  • Data-URI

    • 这种技术是CSS Sprites的替代方法(IE8)。
      Data-URI是指使用图片的数据代替通常使用的图片URI,在下面的例子中,我们就使用它减少了HTTP请求数。
      使用前:
    // 处理前
    .icon-foo {
      background-image: url('foo.png');
    }
    // 处理后
    .icon-foo {
      background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII%3D');
    }
  • 使用其他方式实现图片

    • svg
    • canvas
  • 不要在 标签中调整图像

    • 总是在img标签中设置width和height属性。这样可以防止渲染过程中的重绘和回流。
      知道这个之后,一个开发者将一个700x700px的图像设置为50x50px来显示。
      但是这个开发者不知道的是,大量的没有用的数据也发送到了客户端。
      所以请记住:你可以在标签中定义一个图片的寬高,但不意味着你应该通过这么做来(等比)缩放大图。
  • 图片不失真压缩


## BONUS
  • Confess - Uses PhantomJS to headlessly analyze web pages and generate manifests.
  • Page Speed - The PageSpeed family of tools is designed to help you optimize the performance of your website. PageSpeed Insights products will help you identify performance best practices that can be applied to your site, and PageSpeed optimization tools can help you automate the process.
  • YSlow - YSlow analyzes web pages and suggests ways to improve their performance based on a set of rules for high performance web pages.
  • YSlow for PhantomJS - YSlow for PhantomJS also introduces new output formats for automated test frameworks: TAP (Test Anything Protocol) and JUnit.
  • Grunt-yslow - Grunt task for testing page performance using PhantomJS, a headless WebKit browser.
  • Grunt-perfbudget - A Grunt.js task for enforcing a performance budget (more on performance budgets).
  • Web Tracing Framework - Web Tracing Framework is a set of libraries, tools, and visualizers for the tracing and investigation of complex web applications.

后续

END

THX & Q & A

@mengfanhong
Copy link

good

@kuitos
Copy link

kuitos commented Dec 15, 2015

样式在上,脚本在下

这一条在现代浏览器环境下已经没作用了,浏览器会解析文档然后prefetch脚本。但是我还是建议这么写,因为从测试结果来看,http2.0还是不支持prefetch。

缓存数组长度

这一条作用也不大,现代的js引擎(V8等)会做相关的优化。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants