雅虎军规

雅虎军规

1. 雅虎军规

1.1 14条雅虎军规

  1. 减少Http请求
  2. 使用CDN(内容分发网络)
  3. 添加Exprire/Cache-Control头
  4. 使用Gzip压缩
  5. 将Css放在页面的最上面
  6. 将script放在页面的最下面
  7. 经量避免使用Css Expressions(CSS表达式)
  8. 将脚本文件和样式文件都放在外部文件中
  9. 减少DNS查找
  10. 最小化JavaScript和Css
  11. 避免重定向
  12. 移除重复的脚本
  13. 配置实体标签ETag
  14. 使用Ajax缓存

    1.2 性能优化概况

  • 网络部分
    • 尽量减少HTTP请求数
      • 合并文件
      • 雪碧图
      • 小图Base64
    • 减少DNS查找
      • 开启DNS预解析
    • 使用CND静态资源服务器
    • 避免重定向
    • 杜绝404
  • 缓存
    • 配置ETags
      • 实体标签(ETags),是服务器和浏览器用来决定浏览器缓存中组件与源服务器中的组件是否匹配的一种机制
    • 添上Expires或者Cache-Control HTTP头
    • 使用外链的方式引入JS和CSS(缓存)
  • 内容部分
    • 按需加载组件
    • 预加载组件
    • 减少DOM元素的数量
    • 尽量少用iframe
    • 压缩JavaScript和CSS(代码层面)
  • CSS 部分
    • 避免使用CSS表达式
    • 选择<link>而不是@import
    • 避免使用滤镜
    • 把样式表放在顶部
  • JS 部分
    • 把脚本放在底部
    • 去除重复脚本
    • 减少DOM访问
  • 图片部分
    • 选用合适的图片格式
    • 雪碧图中间少留空白
    • 不要用HTML缩放图片,要小图就去加载小图
    • 用小的可缓存的favicon.ico
  • cookie
    • 给cookie减肥
      • 清除不必要的cookie
      • cookie尽可能小
      • 设置好合适的域
      • 合适的有效期
    • 把静态资源放在不含cookie的域下
      • 当浏览器发送对静态图像的请求时,cookie也会一起发送,而服务器根本不需要这些cookie。
  • 移动端
    • 保证所有组件都小于25K
    • 把组件打包到一个复合文档里
  • 服务器
    • 开启Gzip等压缩
    • 避免图片src属性为空(为空浏览器也会向服务器发送另一个请求)
    • 对Ajax用GET请求
    • 尽早清空缓冲区
    • 使用CDN(内容分发网络)
      • 内容分发网络(CDN)是一组分散在不同地理位置的web服务器,用来给用户更高效地发送内容。

网络优化方案

1.合并资源文件,减少HTTP请求

浏览器并发的HTTP请求是由数量限制的(比如桌面浏览器并发请求可能是8个,手机浏览器是6个),如果一下子并发的几十个请求那么会有很多请求会停下来等,等前面的请求好了下一个再进去,这样就延长了整个页面的加载时间

2.压缩资源文件减小请求大小

文件大小越小当然加载速度就越快。
可对代码进行压缩,去掉空格、注释、变量替换,在传输时,使用gzip等压缩方式也可以降低资源文件的大小。

3.利用缓存机制,尽可能使用缓存减少请求

浏览器是有缓存机制的,在返回资源的时候设置一个cache-control设置过期时间,在过期时间内浏览器会默认使用本地缓存。

但缓存机制也存在一定的问题,因为网站开发是阶段性的,隔一段时间会发布一个新的版本。因为HTTP请求是根据url来定位的,如果资源文件名的url没有发生更改那么浏览器还是会使用缓存,这个时候怎么办那?
这时就需要一个缓存更新机制来让修改过的文件具有一个新的名字。
最简单的方法就是在url后加一个时间戳,但是这会导致只要有新的版本发布就会重新获取所有的新资源。
一个现代流行的方法就是根据文件计算一个hash值,这个hash值是根据文件的更新变化而变化的。 当浏览器获取文件时如果这个文件名有更新那么就会请求新的文件。

4.DNS预解析

现代浏览器在 DNS Prefetch 上做了两项工作:

  1. html 源码下载完成后,会解析页面的包含链接的标签,提前查询对应的域名
  2. 对于访问过的页面,浏览器会记录一份域名列表,当再次打开时,会在 html 下载的同时去解析 DNS

自动解析
浏览器使用超链接的href属性来查找要预解析的主机名。当遇到a标签,浏览器会自动将href中的域名解析为IP地址,这个解析过程是与用户浏览网页并行处理的。但是为了确保安全性,在HTTPS页面中不会自动解析
手动解析

  1. 预解析某域名
  2. <link rel="dns-prefetch" href="//img.alicdn.com">
  3. 强制开启HTTPS下的DNS预解析
  4. <meta http-equiv="x-dns-prefetch-control" content="on">

5.CDN加速

CDN 的原理是尽可能的在各个地方分布机房缓存数据。
因此,我们可以将静态资源尽量使用 CDN 加载,由于浏览器对于单个域名有并发请求上限,可以考虑使用多个 CDN 域名。并且对于 CDN 加载静态资源需要注意 CDN 域名要与主站不同,否则每次请求都会带上主站的 Cookie,平白消耗流量。

6.预加载

  1. 在开发中,可能会遇到这样的情况。有些资源不需要马上用到,但是希望尽早获取,这时候就可以使用预加载。
  2. 预加载其实是声明式的 fetch ,强制浏览器请求资源,并且不会阻塞 onload 事件,可以使用以下代码开启预加载。
  3. 预加载可以一定程度上降低首屏的加载时间,因为可以将一些不影响首屏但重要的文件延后加载,唯一缺点就是兼容性不好。 ```javascript // 1.使用HTML标签 性能优化 - 图1

// 2.使用Image对象

//myPreload.js文件 var image= new Image() image.src=”http://pic26.nipic.com/20121213/6168183 004444903000 2.jpg”

// 3.使用XMLHttpRequest对象,虽然存在跨域问题,但会精细控制预加载过程 var xmlhttprequest=new XMLHttpRequest(); xmlhttprequest.onreadystatechange=callback; xmlhttprequest.onprogress=progressCallback; xmlhttprequest.open(“GET”,”http://image.baidu.com/mouse,jpg",true); xmlhttprequest.send(); function callback(){ if(xmlhttprequest.readyState==4&& xmlhttprequest.status==200){ var responseText=xmlhttprequest.responseText; }else{ console.log(“Request was unsuccessful:”+xmlhttprequest.status); } } function progressCallback(e){ e=e || event; if(e.lengthComputable){ console.log(“Received”+e.loaded+”of”+e.total+”bytes”) } }

  1. 使用预渲染后,只需加载index.htmlapp.css即可看到页面的部分形式。<br />预渲染的最佳时间莫过于预渲染骨架屏了。静态的骨架屏预渲染后保存在本地,基本永久使用,只要骨架屏返回并渲染了,用户是看不到白屏的(诸如以上只有topNav的那种),而骨架屏作为布局简单,样式普通的一个小组件,构建后返回的html在浏览器渲染当然速度也是极快的,用户体验++
  2. <a name="76e234d6"></a>
  3. ## 7.图片优化
  4. 1. 不用图片。很多时候会使用到很多修饰类图片,其实这类修饰图片完全可以用 CSS 去代替。
  5. 1. 对于移动端按理说,图片不需要加载原图,可请求裁剪好的图片
  6. 1. 小图使用base64格式
  7. 1. 将多个图标文件整合到一张图中(雪碧图)
  8. 1. 采用正确的图片格式
  9. - 对于能够显示 WebP 格式的浏览器尽量使用 WebP 格式。因为 WebP 格式具有更好的图像数据压缩算法,能带来更小的图片体积,而且拥有肉眼识别无差异的图像质量,缺点就是兼容性并不好
  10. - 色彩很多的使用 JPEG
  11. - 色彩种类少的使用 PNG,有的可用SVG代替
  12. <a name="df0ccdcd"></a>
  13. ## 8.预渲染
  14. > [!NOTE]
  15. > 预渲染:构建阶段生成匹配预渲染路径的 html 文件(注意:每个需要预渲染的路由都有一个对应的 html)。构建出来的 html 文件已有部分内容。
  16. 非预渲染需要加载到1(index.html),2app.css),3(manifest.js),4(vender.js),用户才能看到页面
  17. ```javascript
  18. 1 index.html
  19. 2 app.css 样式
  20. 3 manifest.js webpack manifest
  21. 4 vender.js 第三方库
  22. 5 app.js 业务逻辑
  23. 6 0.js 路由分包文件

重绘回流过程

1. 浏览器的渲染过程,DOM 树和渲染树的区别?

image.png

  1. HTML 经过解析生成 DOM树; CSS经过解析生成 Style Rules。 二者一结合生成了Render Tree。
  2. 通过layout计算出DOM要显示的宽高、位置、颜色。
  3. 最后渲染在界面上,用户就看到了

    2. 浏览器的渲染过程

  4. 解析 HTML 构建 DOM(DOM 树),并行请求 css/image/js

  5. CSS 文件下载完成,开始构建 CSSOM(CSS 树)
  6. CSSOM 构建结束后,和 DOM 一起生成 Render Tree(渲染树)
  7. 布局(Layout):计算出每个节点在屏幕中的位置
  8. 显示(Painting):通过显卡把页面画到屏幕上

    3. DOM 树 和 渲染树 的区别?

  9. DOM 树与 HTML 标签一一对应,包括 head 和隐藏元素

  10. 渲染树不包括 head 和隐藏元素,大段文本的每一个行都是独立节点,每一个节点都有对应的 css 属性

    4. CSS会阻塞DOM解析吗?

  11. 对于一个HTML文档来说,不管是内联还是外链的css,都会阻碍后续的dom渲染,但是不会阻碍后续dom的解析。

  12. 当css文件放在<head>中时,虽然css解析也会阻塞后续dom的渲染,但是在解析css的同时也在解析dom,所以等到css解析完毕就会逐步的渲染页面了。

    5. 重绘和回流(重排)的区别和关系?

  13. 重绘:当渲染树中的元素外观(如:颜色)发生改变,不影响布局时,产生重绘

  14. 回流:当渲染树中的元素的布局(如:尺寸、位置、隐藏/状态状态)发生改变时,产生重绘回流
  15. 注意:JS 获取 Layout 属性值(如:offsetLeft、scrollTop、getComputedStyle 等)也会引起回流。因为浏览器需要通过回流计算最新值
  16. 回流必将引起重绘,而重绘不一定会引起回流

    5.1 触发回流reflow

  17. width/height/border/margin/padding的修改,如width=778px;

  18. 动画,:hover等伪类引起的元素表现改动,display=none等造成页面回流;
  19. appendChild等DOM元素操作;
  20. font类style的修改;
  21. background的修改,注意着字面上可能以为是重绘,但是浏览器确实回流了,经过浏览器厂家的优化,部分background的修改只触发repaint,当然IE不用考虑;
  22. scroll页面,这个不可避免;
  23. resize页面,桌面版本的进行浏览器大小的缩放,移动端的话,还没玩过能拖动程序,resize程序窗口大小的多窗口操作系统。
  24. 读取元素的属性(这个无法理解,但是技术达人是这么说的,那就把它当做定理吧):读取元素的某些属性(offsetLeft、offsetTop、offsetHeight、offsetWidth、scrollTop/Left/Width/Height、clientTop/Left/Width/Height、getComputedStyle()、currentStyle(in IE));

    5.2 触发重绘repaint

  25. color的修改,如color=#ddd;

  26. text-align的修改,如text-align=center;
  27. a:hover也会造成重绘。
  28. :hover引起的颜色等不导致页面回流的style变动。

    6. 如何最小化重绘(repaint)和回流(reflow)?

    6.1 性能问题

    以下操作会导致性能问题:

  29. 改变 window 大小

  30. 改变字体
  31. 添加或删除样式
  32. 文字改变
  33. 定位或者浮动
  34. 盒模型

    3.2 解决方法

  35. 需要要对DOM元素进行复杂的操作时,可以先隐藏(display:”none”),操作完成后再显示

  36. 需要创建多个 DOM 节点时,使用 DocumentFragment 创建完后一次性的加入 document,或使用字符串拼接方式构建好对应HTML后再使用innerHTML来修改页面
  37. 缓存 Layout 属性值,如:var left = elem.offsetLeft; 这样,多次使用 left 只产生一次回流
  38. 避免用 table 布局(table 元素一旦触发回流就会导致 table 里所有的其它元素回流)
  39. 避免使用 css 表达式(expression),因为每次调用都会重新计算值(包括加载页面)
  40. 尽量使用 css 属性简写,如:用 border 代替 border-width, border-style, border-color
  41. 批量修改元素样式:elem.className 和 elem.style.cssText 代替 elem.style.xxx

缓存

[!NOTE] Http 的缓存主要利用 header 里的Cache-control 和 ETag

1.Cache-control

1.1 Cache-control主要字段

  • public
    • 指HTTP请求返回的资源在所经过的所有路径包括一些中间代理服务器以及发出这个请求的客户端浏览器都可以进行缓存
  • private
    • 代表发起请求的浏览器才可以进行缓存
  • no-cache
    • 指可以存缓存,但是每次使用都需要去服务端验证
  • no-store
    • 本地和代理服务器都不允许去缓存
  • no-transform

    • 不允许代理/缓存服务器转换文件格式

      1.1.1 到期

  • max-age=<seconds\>

    • 缓存到期时间
  • s-maxage=<seconds\>
    • 代理服务器专用
  • max-stale=<seconds\>

    • 指示客户机可以使用超出max-age时间的响应

      1.1.2 重新验证

  • must-revalidate

    • 设置了max-age的资源过期后必须到源服务端验证资源是否还可用
  • proxy-revalidate
    • (缓存服务器用)设置了max-age的资源过期后必须到源服务端验证资源是否还可用

      1.2 Etag

      1.2.1 ETag资源标识码

      即用来进行对比缓存,Etag 是服务端资源的一个标识码

当客户端发送第一次请求时服务端会下发当前请求资源的标识码 Etag,下次再请求时,客户端则会通过 header 里的 If-None-Match 将这个标识码 Etag 带上,服务端将客户端传来的 Etag 与最新的资源 Etag 做对比,如果一样,则表示资源没有更新,返回 304。

2. 缓存方案

2.1 需求

有的静态资源会设置一个较长的缓存时间,但是我们希望用户还是能使用最新的资源。

2.2 解决方案

在打包完成的文件名上加上一串哈希码,这个哈希码是根据内容进行的哈希计算。 所以,如果你的内容文件没有变,那么这个hash码不会变,即这个静态资源的url没有变。 而如果内容有变,那么hash码也会变,浏览器就会去请求新的资源请求。

2.3 普通的缓存机制

image.png

2.4 资源验证

如果给Cache-Control设置了no-cache后,每次要使用资源时浏览器都要到服务器验证缓存是否过期。 如果直接使用缓存,返回码:304

2.5 如何验证资源是否过期:

  • Last-Modified(上次修改时间)
    • 配合 If-Modified-Since 或 If-Unmodified-Since 使用
    • 如果请求的资源头中有Last-Modified这个头,这个头指定了一个时间。那么浏览器重新访问资源时就会带上If-Modified-Since这个头,其时间是Last-Modified的时间,服务器就会拿这个时间去对比上次修改的时间,然后告诉浏览器是否可以直接使用。
  • Etag (数据签名)
    • 资源会依据它的内容产生一个唯一的数据签名,如果资源有更新,那么Etag就会发生变化。
    • 配合 If-Match 或 If-None-Match 使用

CDN

1. 描述一下CDN的概念和底层原理?

1.1 基本概念

[!NOTE] CDN(Content Delivery Network,内容分发网络)是构建在现有互联网基础之上的一层智能虚拟网络,通过在网络各处部署节点服务器,实现将源站内容分发至所有CDN节点,使用户可以就近获得所需的内容。CDN服务缩短了用户查看内容的访问延迟,提高了用户访问网站的响应速度与网站的可用性,解决了网络带宽小、用户访问量大、网点分布不均等问题。

1.2 加速原理

当用户访问使用CDN服务的网站时,本地DNS服务器通过CNAME方式将最终域名请求重定向到CDN服务。CDN通过一组预先定义好的策略(如内容类型、地理区域、网络负载状况等),将当时能够最快响应用户的CDN节点IP地址提供给用户,使用户可以以最快的速度获得网站内容。使用CDN后的HTTP请求处理流程如下:

1.2.1 CDN节点有缓存场景

image.png

  1. 用户在浏览器输入要访问的网站域名,向本地DNS发起域名解析请求。
  2. 域名解析的请求被发往网站授权DNS服务器。
  3. 网站DNS服务器解析发现域名已经CNAME到了www.example.com.c.cdnhwc1.com。
  4. 请求被指向CDN服务。
  5. CDN对域名进行智能解析,将响应速度最快的CDN节点IP地址返回给本地DNS。
  6. 用户获取响应速度最快的CDN节点IP地址。
  7. 浏览器在得到速度最快节点的IP地址以后,向CDN节点发出访问请求。
  8. CDN节点将用户所需资源返回给用户。

    1.2.2 CDN节点无缓存场景

  9. 用户在浏览器输入要访问的网站域名,向本地DNS发起域名解析请求。

  10. 域名解析的请求被发往网站授权DNS服务器。
  11. 网站DNS服务器解析发现域名已经CNAME到了www.example.com.c.cdnhwc1.com。
  12. 请求被指向CDN服务。
  13. CDN对域名进行智能解析,将响应速度最快的CDN节点IP地址返回给本地DNS。
  14. 用户获取响应速度最快的CDN节点IP地址。
  15. 浏览器在得到速度最快节点的IP地址以后,向CDN节点发出访问请求。
  16. CDN节点回源站拉取用户所需资源。
  17. 将回源拉取的资源缓存至节点。
  18. 将用户所需资源返回给用户。

    [!NOTE] 名称解释:CNAME别名解析是将域名指向一个网址(域名)

虚拟滚动技术

1. 插入几万个 DOM,如何实现页面不卡顿?(面试加分项)

  1. 肯定不能一次性把几万个 DOM 全部插入,这样肯定会造成卡顿,所以解决问题的重点应该是如何分批次部分渲染 DOM。部分人应该可以想到通过 requestAnimationFrame 的方式去循环的插入 DOM,其实还有种方式去解决这个问题:虚拟滚动(virtualized scroller)。
  2. 这种技术的原理就是只渲染可视区域内的内容,非可见区域的那就完全不渲染了,当用户在滚动的时候就实时去替换渲染的内容。

vScroll.png

  1. 从上图中我们可以发现,即使列表很长,但是渲染的 DOM 元素永远只有那么几个,当我们滚动页面的时候就会实时去更新 DOM,这个技术就能顺利解决这发问题。如果你想了解更多的内容可以了解下这个 react-virtualized

    Webpack性能优化

    1. 谈一下如何使用Webpack进行性能优化?

    1.1 减小打包后文件体积

    1.1.1 按需加载

    1.1.2 Tree Shaking

    1.1.3 Scope Hoisting

    1.2 加快打包速度

    1.2.1 优化 Loader

    1.2.2 HappyPack

    1.2.3 DllPlugin

    1.2.4 代码压缩

    1.2.6 Webpack长缓存优化