浏览器工做原理及web 性能优化(上)

浏览器工做原理

1、浏览器简介

  • 分类:如今主要有五大主流浏览器: Chrome, Internet Explorer, Firefox, Safari and Opera.移动端上是Android Browser, iPhone, Opera Mini and Opera Mobile, UC Browser, the Nokia S40/S60 browsers,除了Opera,这些浏览器都是基于WebKit内核的(目前可能有变)。
  • 功能 :根据W3C制定的一系列规范,从服务端请求并渲染资源
  • 广泛外观:地址栏,前进后退,书签,刷新及取消,主页
  • 深层结构:下边主要介绍———渲染引擎及JS引擎
    • 用户界面(User Interface) :包括地址栏、前进/后退按钮、书签菜单等。除了浏览器主窗口显示的您请求的页面外,其余显示的各个部分都属于用户界面。
    • 浏览器引擎(Browser engine): 在用户界面和呈现引擎之间传送指令。
    • 呈现引擎(Rendering engine): 负责显示请求的内容。若是请求的内容是 HTML,它就负责解析 HTML 和 CSS 内容,并将解析后的内容显示在屏幕上。
    • 网络(Networking) : 用于网络调用,好比 HTTP 请求。其接口与平台无关,并为全部平台提供底层实现。
    • 用户界面后端(UI backend):用于绘制基本的窗口小部件,好比组合框和窗口。其公开了与平台无关的通用接口,而在底层使用操做系统的用户界面方法。
    • JavaScript 解释器(JS Interpreter):用于解析和执行 JavaScript 代码。
    • 数据存储(Datapersistence):这是持久层。浏览器须要在硬盘上保存各类数据,例如 Cookie。新的 HTML 规范 (HTML5) 定义了“网络数据库”,这是一个完整(可是轻便)的浏览器内数据库。

2、渲染引擎

  • 分类:不一样浏览器用不一样渲染引擎。

Internet Explorer uses Trident, Firefox uses Gecko, Safari uses WebKit. Chrome and Opera (from version 15) use Blink, a fork of WebKit.WebKit 是一个开源渲染引擎,起初做为Linux platform的引擎,后被 Apple应用于Mac. 详见 webkit.org.css

  • 加载:

    • 浏览器根据 DNS 服务器获得域名的 IP 地址
    • 向这个 IP 的机器发送 HTTP 请求
    • 服务器收到、处理并返回 HTTP 请求
    • 浏览器获得返回内容

客户端:如在浏览器输入https://www.baidu.com/,通过 DNS 解析,查到baidu.com对应的 IP(不一样时间、地点对应的 IP 可能会不一样),浏览器向该 IP 发送 HTTP 请求。html

服务端:服务器接收到 HTTP 请求,经计算,返回 HTTP 请求前端

  • 过程以下:
    在Chrome开发者工具中的Timeline中能够详细看到具体过程。

  • 内容以下:

  • 渲染:

浏览器对请求的呈现。默认渲染引擎能够呈现html,xml及图片。(经过插件)也能够呈现其它数据,好比pdf等。 目前只考虑html和css方面。html5

渲染主流程:

Figure : Rendering engine basic flow

Figure : WebKit main flow

content tree:在此,渲染引擎解析html文档并将元素转换成DOM节点。node

render tree:在此,渲染引擎解析style(外部css文件或内联style)并转换。react

这是一个渐进式过程. 为保证好的UED,渲染引擎尽早展示内容. 在开始构建并展示render树以前,它不会等全部html被解析。部份内容被解析并呈现,同时进程继续解析网络中不断请求到的其他内容。webpack

具体渲染过程
  • 根据 HTML 结构生成 DOM 树
  • 根据 CSS 生成 CSSOM
  • 将 DOM 和 CSSOM 整合造成 RenderTree
  • 根据 RenderTree 开始渲染和展现
  • 遇到<script>时,会执行并阻塞渲染

浏览器拿到了 server 端返回的 HTML 内容后,开始解析并渲染。最初拿到的内容就是一堆字符串,必须先结构化成计算机擅长处理的基本数据结构--- DOM 树 (最基本的数据结构之一)。git

解析过程当中,若是遇到<link href="..."><script src="...">这种外链加载 CSS 和 JS 的标签,浏览器会异步下载,下载过程和上文中下载 HTML 的流程同样。只不过,这里下载下来的字符串是 CSS 或者 JS 格式的。实际应用中,经常使用媒体类型(media type)和媒体查询(media query)来解除对渲染的阻塞。github

<link href="index.css" rel="stylesheet"> <--阻塞-->
<link href="print.css" rel="stylesheet" media="print"><--加载&& !阻塞,仅在print时实用-->
<link href="other.css" rel="stylesheet" media="(min-width: 30em) and (orientation: landscape)"><--符合条件时阻塞-->
复制代码
  • 查看下边一段代码:
<p>根据 HTML 结构生成 DOM 树,稍等。。。</p>
<script src="app.js"></script>
<p>根据 CSS 生成 CSSOM,稍等。。。</p>
<script>console.log("inline")</script>
<p>将 DOM 和 CSSOM 整合造成 RenderTree</p>
复制代码

这段html被解析时会被js代码阻塞(加载+执行),所以常把css放在头部(保证渲染),把js放在底部(保证非阻塞)。web

  • Normal execution <script> 浏览器默认:当执行script时解析html代码暂停。对于慢服务和重script的状况意味着webpage呈现将被延后。
  • Deferred execution <script defer> 简而言之:推迟script执行直到html解析结束。该属性的好处就是DOM渲染友好,对于你的script。然而,并不是每一个浏览器支持该属性,故不要期望它!
  • Asynchronous execution <script async> 不用管script什么时候好?async对于两个都是最好的:html解析可能持续且script将被执行一旦ready。对script标签推荐这个属性,如google analytics所分析。
document.createElement("script").async
// true
复制代码
<script src="app1.js" defer></script>
<script src="app2.js" defer></script>

<script src="init1.js" async></script>
<script src="init2.js" async></script>
复制代码
  • 浏览器的容错机制

您在浏览 HTML 网页时历来不会看到“语法无效”的错误。这是由于浏览器会纠正任何无效内容,而后继续工做。

1. 明显不能在某些外部标签中添加的元素。在此状况下,咱们应该关闭全部标签,直到出现禁止添加的元素,而后再加入该元素。
2. 咱们不能直接添加的元素。这极可能是网页做者忘记添加了其中的一些标签(或者其中的标签是可选的)。这些标签可能包括:HTML HEAD BODY TBODY TR TD LI(还有遗漏的吗?)。
3. 向 inline 元素内添加 block 元素。关闭全部 inline 元素,直到出现下一个较高级的 block 元素。
4. 若是这样仍然无效,可关闭全部元素,直到能够添加元素为止,或者忽略该标记。
复制代码

CSS 解析

和 HTML 不一样,CSS 是上下文无关的语法,可使用简介中描述的各类解析器进行解析。事实上,CSS 规范定义了 CSS 的词法和语法。

  • WebKit CSS 解析器 WebKit 使用 Flex 和 Bison 解析器生成器,经过 CSS 语法文件自动建立解析器。正如咱们以前在解析器简介中所说,Bison 会建立自下而上的移位归约解析器。Firefox 使用的是人工编写的自上而下的解析器。这两种解析器都会将 CSS 文件解析成 StyleSheet 对象,且每一个对象都包含 CSS 规则。CSS 规则对象则包含选择器和声明对象,以及其余与 CSS 语法对应的对象。
图:解析 CSS

处理脚本和样式表的顺序

  • 脚本

:遇到 <script>文档的解析将中止,直到脚本执行完毕。若是脚本是外部的,那么解析过程会中止,直到从网络同步抓取资源完成后再继续。HTML5 增长了一个选项----“defer”,这样不会中止文档解析,而是等到解析结束才执行.

  • 预解析 WebKit 和 Firefox 都进行了这项优化。**在执行脚本时,其余线程会解析文档的其他部分,找出并加载须要经过网络加载的其余资源。**经过这种方式,资源能够在并行链接上加载,从而提升整体速度。请注意,预解析器不会修改 DOM 树,而是将这项工做交由主解析器处理;预解析器只会解析外部资源(例如外部脚本、样式表和图片)的引用。

  • 样式表: 理论上来讲,应用样式表不会更改 DOM 树,所以彷佛没有必要等待样式表并中止文档解析

  • render树构建: 在 DOM 树构建的同时,浏览器还会构建:render树---按照正确的顺序绘制内容。

  • render树和 DOM 树的关系:呈现器是和 DOM 元素相对应的,但并不是一一对应。非可视化的 DOM 元素不会插入呈现树中,例如“head”元素。若是元素的 display 属性值为“none”,那么也不会显示在呈现树中(可是 visibility 属性值为“hidden”的元素仍会显示)。

Web 安全

常见的web攻击方式:

  • SQL 注入:输入时进行了恶意的 SQL 拼装,致使最后生成的 SQL 有问题。攻击方式低端,常出如今比较低端的系统。

  • XSS(Cross Site Scripting,跨站脚本攻击)

前端最多见的攻击方式,不少网站(如 阮一峰博客)都被 XSS 攻击过。

原理:经过某种方式(发布文章、发布评论等)将一段特定的 JS 代码隐蔽地输入进去。JS 代码一旦执行,那可就不受控制了,由于它跟网页原有的 JS 有一样的权限,例如能够获取 server 端数据、能够获取 cookie 等。因而,攻击就这样发生了。

预防:最根本的方式,用正则表达式进行转换处理,如:

< 替换为:&lt;
> 替换为:&gt;
& 替换为:&amp;
‘ 替换为:&#x27;
” 替换为:&quot;
复制代码

另外,还能够经过对 cookie控制,好比对敏感的 cookie 增长http-only限制,让 JS 获取不到 cookie 的内容。

  • CSRF(Cross-site request forgery,跨站请求伪造) 理论基础:借助了一个 cookie的特性,劫持操做者的权限来偷偷地完成某个操做,而不是拿到用户的信息。

预防 :加入各个层级的权限验证,如涉及现金交易,必需要输入密码或者指纹才行等。

浏览器从新渲染(re-render):重绘(repaint)与重排(reflow)

从新渲染,就须要从新生成布局和从新绘制。前者叫作"重排"(reflow),后者叫作"重绘"(repaint)。"重绘"不必定须要"重排","重排"必然致使"重绘"。重排和重绘会不断触发,这是不可避免的。可是,它们很是耗费资源,是致使网页性能低下的根本缘由。提升网页性能,就是要下降"重排"和"重绘"的频率和成本,尽可能少触发从新渲染。

  • 触发从新渲染的常见状况:
    • 修改DOM
    • 修改样式表
    • 用户事件(好比鼠标悬停、页面滚动、输入框键入文字、改变窗口大小等等)
    • 访问元素属性:
      • offsetTop/offsetLeft/offsetWidth/offsetHeight
      • scrollTop/scrollLeft/scrollWidth/scrollHeight
      • clientTop/clientLeft/clientWidth/clientHeight
      • getComputedStyle()
  • 提升性能的技巧:
    • css:

      • display(none->block)
      • position(absolute,fixed)
      • visibility(hidden)
    • js:

      • 使用优秀类库的Virtual DOM(React,Vue)
      • 注意做用域
        • 避免全局查找
        • 避免with
      • 选择正确的方法
        • 避免不必的查找(性能部分的一部分是和解决问题的算法和方法相关的)
        • 优化循环
        • 展开循环
        • 避免双重解释
        • 其它
          • 原生方法较快:
          • switch语句较快
          • 位运算符较快
      • 最小化语句数
        • 多个变量声明
        • 插入迭代值
        • 使用数组和对象字面量
      • 优化DOM交互(以下)
    • BOM:

      • window.requestAnimationFrame
      • window.requestIdleCallback
    • DOM:

      • document.createDocumentFragment:最小化现场更新
      • innerHTML:要不使用标准DOM方法建立一样的DOM快得多(内部方法是编译好而非解释执行的)。
      • 事件代理:页面处理程序的数量和页面响应UED速度负相关。事件处理程序本质上是一种函数,是一种对象,存放在内存中,设置大量的事件处理程序会使内存中的对象变多,Web 程序的性能会变得愈来愈差,用户体验很很差。
      • 注意HTMLCollection:最小化对它们的访问,如下会返回HTMLCollection对象
        • getElementByTagName
        • childNodes
        • attributes
        • 特殊集合:document.forms,document.images etc.
      • cloneNode
      • 集中DOM的读写操做
      • 使用 SSR 后端渲染,数据直接输出到 HTML 中,减小浏览器使用 JS 模板渲染页面 HTML 的时间
    • HTTP: 减小页面体积,提高网络加载

      • 静态资源的压缩合并(JS 代码压缩合并、CSS 代码压缩合并、雪碧图)
      • 静态资源缓存(资源名称加 MD5 戳)
      • 使用 CDN 让资源加载更快

应用示例

  • js中应用到的简单算法

标记名称 描述
O(1) 常数:无论有多少值,执行时间恒定,通常表示简单值和存储在变量中的值(数组元素访问)
O(logn) 对数:执行总时间与数量相关,但要完成算法并不必定获取每一个值。如二分查找
O(n) 线性:执行总时间和数量直接相关。如遍历操做
O(n2) 平方:执行总时间与数量有关,每一个值至少要获取n次。如插入排序
  • 代码示例

  1. 避免全局查找

测试网页

// bad(3次全局查找) 
function updateUI(){
console.time()
	var images=document.getElementsByTagName('img')
for(var i=0,len=images.length;i<len;i++){
	images[i].title=document.title+'image'+i;
}
return console.timeEnd()
}
// default: 0.5439453125ms
// good(一次全局查找)
function updateUI(){
console.time()
var doc = document
	var images=doc.getElementsByClassName('img')
for(var i=0,len=images.length;i<len;i++){
	images[i].title=doc.title+'image'+i;
}
return console.timeEnd()
}
// default: 0.120849609375ms
复制代码

2.避免没必要要的属性查找(见JS常见算法类型) 最简单最便捷的算法是常数O(1)

// 四次查找(5,value,10,sum)
var value = 5
var sum = value + 10 
console.log(sum)
// default: 0.375ms
复制代码

3.使用变量和数组要比访问对象上属性(O(n))更高效。

// good
var values = [1, 2, 3]
var sum = values[0] + values[1]
console.log(sum)
// default: 0.298095703125ms
// bad
var values = {a:1, b:2}
var sum = values.a + values.b
console.log(sum)
// default: 0.302978515625ms
复制代码

4.⚠️注意获取单个值的属性查找

// bad
var query = window.location.href.substring(window.location.href.indexOf('?'))
// default: 0.02783203125ms
// good
var url = window.location.href
var query = url.substring(url.indexOf('?'))
// default: 0.02001953125ms
复制代码
  1. 优化循环
// bad
var values=new Array().fill(10000)
for(var i=0;i<values.length;i++){i}
// default: 0.101806640625ms
// good(使用减值迭代:将终止条件从values.length的O(n)调用简化成了O(1)调用)
for(var i = values.length-1;i>0;i--){}
// default: 0.01708984375ms (一个数量级)
// good(后测试循环:循环部分已彻底优化,任何进一步的优化只能在处理语句中进行了),这种写法的弊端就是可读性不好
var i = values.length - 1
if(i > -1){
    do{
        //
    }while(--i >= 0)
}
// default: 0.011962890625ms
复制代码

6.避免双重解释(JS 代码运行的同时必须新启动一个解析器来解析新的代码。实例化一个新的解析器有不容忽视的开销)

eval("alert('hi')")// bad
var say = new Function("alert('hi')")// bad
setTimeout('alert("hi")',500)// bad
alert('hi')// good
var say = function (){
    alert('hi')
}// good
setTimeout(function (){
    alert('hi')
},500)// good
复制代码
  1. 最小化语句数
// 多个变量声明
var count = 0,
    color = 'red',
    values = [],
    now = new Date()
// 插入迭代值
var value = values[i]; i ++ // bad
var value = values[i++] // good
// 使用数组和对象字面量
var values = new Array(); values[0] = 1; values[1] = 2 // bad(3个语句)
var person = new Object();
person.a = 1;
person.b = 2 // bad(3个语句)
var values = [1,2] // good(2个语句建立和初始化数组)
var person = {a:1,b:2}// good(2个语句建立和初始化对象)
复制代码
  1. 优化DOM交互(因DOM内部包含了很是多的属性及方法,DOM 交互很是耗时)
// DOM里的内容
var div = document.createElement('div'), result =  ''
for(var i in div){
    result += i + ' '
}
/*
"align title lang translate dir dataset hidden tabIndex accessKey draggable spellcheck autocapitalize contentEditable isContentEditable inputMode offsetParent offsetTop offsetLeft offsetWidth offsetHeight style innerText outerText onabort onblur oncancel oncanplay oncanplaythrough onchange onclick onclose oncontextmenu oncuechange ondblclick ondrag ondragend ondragenter ondragleave ondragover ondragstart ondrop ondurationchange onemptied onended onerror onfocus oninput oninvalid onkeydown onkeypress onkeyup onload onloadeddata onloadedmetadata onloadstart onmousedown onmouseenter onmouseleave onmousemove onmouseout onmouseover onmouseup onmousewheel onpause onplay onplaying onprogress onratechange onreset onresize onscroll onseeked onseeking onselect onstalled onsubmit onsuspend ontimeupdate ontoggle onvolumechange onwaiting onwheel onauxclick ongotpointercapture onlostpointercapture onpointerdown onpointermove onpointerup onpointercancel onpointerover onpointerout onpointerenter onpointerleave nonce click focus blur namespaceURI prefix localName tagName id className classList slot attributes shadowRoot assignedSlot innerHTML outerHTML scrollTop scrollLeft scrollWidth scrollHeight clientTop clientLeft clientWidth clientHeight onbeforecopy onbeforecut onbeforepaste oncopy oncut onpaste onsearch onselectstart previousElementSibling nextElementSibling children firstElementChild lastElementChild childElementCount onwebkitfullscreenchange onwebkitfullscreenerror setPointerCapture releasePointerCapture hasPointerCapture hasAttributes getAttributeNames getAttribute getAttributeNS setAttribute setAttributeNS removeAttribute removeAttributeNS hasAttribute hasAttributeNS getAttributeNode getAttributeNodeNS setAttributeNode setAttributeNodeNS removeAttributeNode closest matches webkitMatchesSelector attachShadow getElementsByTagName getElementsByTagNameNS getElementsByClassName insertAdjacentElement insertAdjacentText insertAdjacentHTML requestPointerLock getClientRects getBoundingClientRect scrollIntoView scrollIntoViewIfNeeded animate before after replaceWith remove prepend append querySelector querySelectorAll webkitRequestFullScreen webkitRequestFullscreen attributeStyleMap scroll scrollTo scrollBy createShadowRoot getDestinationInsertionPoints computedStyleMap ELEMENT_NODE ATTRIBUTE_NODE TEXT_NODE CDATA_SECTION_NODE ENTITY_REFERENCE_NODE ENTITY_NODE PROCESSING_INSTRUCTION_NODE COMMENT_NODE DOCUMENT_NODE DOCUMENT_TYPE_NODE DOCUMENT_FRAGMENT_NODE NOTATION_NODE DOCUMENT_POSITION_DISCONNECTED DOCUMENT_POSITION_PRECEDING DOCUMENT_POSITION_FOLLOWING DOCUMENT_POSITION_CONTAINS DOCUMENT_POSITION_CONTAINED_BY DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC nodeType nodeName baseURI isConnected ownerDocument parentNode parentElement childNodes firstChild lastChild previousSibling nextSibling nodeValue textContent hasChildNodes getRootNode normalize cloneNode isEqualNode isSameNode compareDocumentPosition contains lookupPrefix lookupNamespaceURI isDefaultNamespace insertBefore appendChild replaceChild removeChild addEventListener removeEventListener dispatchEvent "
*/
复制代码
  1. 最小化现场更新
// bad
console.time()
var list = document.createElement('ul'),
    item,
    i
for(i=0;i<10000;i++){
    item = document.createElement('li')
    list.appendChild(item)
    item.appendChild(document.createTextNode('item' + i))
}
document.body.appendChild(list)
console.timeEnd()
// default: 26.902099609375ms

// good
console.time()
var list = document.createElement('ul'),
    fragment = document.createDocumentFragment(),
    item,
    i
for(i=0;i<10000;i++){
    item = document.createElement('li')
    fragment.appendChild(item)
    item.appendChild(document.createTextNode('item' + i))
}
document.body.appendChild(fragment)
console.timeEnd()
// VM7017:12 default: 29.4169921875ms ???
// good (使用innerHTML(编译好的而非解释执行的))
console.time()
var list = document.createElement('ul'),
    html = '',
    i
for(i=0;i<10000;i++){
    // list.innerHTML += "<li>Item " + i + "</li>" // 避免
   html += "<li>Item " + i + "</li>"
}
list.innerHTML = html
document.body.appendChild(list)
console.timeEnd()
//default: 25.760986328125ms
复制代码
  1. 最小化对HTMLColletion的访问
console.time()
var images = document.getElementsByTagName('img'),
i,
image,
len,
temp
for(i = 0, len=images.length;i<len;i++){
    image = images[i]// 保存当前image,避免了对images的访问
	temp=image+Image
}
console.timeEnd()
// default: 0.06591796875ms
console.time()
var images = document.getElementsByTagName('img'),
i,
len,
temp
for(i = 0, len=images.length;i<len;i++){
	temp=images[i]+images[i]
}
console.timeEnd()
// VM6253:9 default: 0.115966796875ms
复制代码

静态资源缓存

经过连接名称控制缓存

<script src="a.js"></script>
复制代码

只有内容改变的时候,连接名称才会改变

<script src="b.js"></script>
复制代码

可经过前端构建工具根据文件内容,为文件名称添加 MD5 后缀。

使用CDN(专业的加载优化方案)让资源加载更快

<script src="https://cdn.bootcss.com/zepto/1.0rc1/zepto.min.js"></script>
复制代码

事件节流:函数节流(throttle)与函数去抖(debounce)

  • 概念:
    • 函数节流:若是将水龙头拧紧直到水是以水滴的形式流出,那你会发现每隔一段时间,就会有一滴水流出。也就是说会预先设定一个执行周期,当调用动做的时刻大于等于执行周期则执行该动做,而后进入下一个新周期。
    • 函数去抖:若是用手指一直按住一个弹簧(debounce),它将不会弹起直到你松手为止。也就是说当调用动做n毫秒后,才会执行该动做,若在这n毫秒内又调用此动做则将从新计算执行时间。
  • 为何要节流?

因为事件频繁被触发,于是频繁执行DOM操做、资源加载等重行为,致使UI停顿甚至浏览器崩溃。

  • 什么时候考虑节流?

    • window对象的resize、scroll事件;
    • 拖拽时的mousemove事件;
    • 游戏中的mousedown、keydown、mouseenter,mouseover事件;
    • 文字输入input、blur、自动完成的keyup事件等。
  • 具体作法:

// throttle
var throttle = function(delay, action){
  var last = 0return function(){
    var curr = +new Date()
    if (curr - last > delay){
      action.apply(this, arguments)
      last = curr 
    }
  }
}
// debounce
var textarea = document.getElementById('btn')
var timeoutId
textarea.addEventListener('keyup', function () {
    if (timeoutId) {
        clearTimeout(timeoutId)
    }
    timeoutId = setTimeout(function () {
        // 触发 change 事件
    }, 100)
})
复制代码

web性能优化(web performance)

为何要性能优化

  • 留住用户(Performance is about retaining users)
  • 提高转化率(Performance is about improving conversions)
转化率就是金钱
  • 关乎用户体验(Performance is about the user experience)
  • 以人为本(Performance is about people)

如何去优化

要发送什么(Mind what resources you send)

构建高性能应用程序的有效方法是审核发送给用户的资源。虽然Chrome开发人员工具中的网络面板能够很好地总结给定页面上使用的全部资源,但若是您到目前为止还没有考虑性能,那么知道从哪里开始可能会使人生畏。如下是一些建议:

  • 若是您使用Bootstrap或Foundation来构建UI,请问本身是否有必要。这些抽象添加了浏览器必须下载,解析和应用于页面的大量CSS,全部这些都是在特定于站点的CSS进入图片以前。 Flexbox和Grid在使用相对较少的代码建立简单和复杂布局方面很是出色。因为CSS是一种render阻塞资源,所以CSS框架的开销可能会显着延迟渲染。您应该经过消除没必要要的开销来寻求加速渲染,而非尽量依赖于浏览器中的工具。

  • JavaScript库很方便,但并不老是必要的。以jQuery为例:因为querySelectorquerySelectorAll等方法,元素选择获得了极大的简化。使用addEventListener能够轻松进行事件绑定。classList,setAttributegetAttribute提供了使用类和元素属性的简便方法。若是你必须使用类库,研究更精简的替代品。例如,Zepto是一个较小的jQuery替代品,Preact是React的一个小得多的替代品。

  • 并不是全部网站都须要是单页面应用程序(SPA),由于它们常常普遍使用JavaScript。 JavaScript是咱们在字节的web字节上提供的最昂贵的资源,由于它不只必须下载,还必须解析,编译和执行。例如,具备优化前端架构的新闻和博客站点能够像传统的多页体验同样表现良好。

如何发送(Mind how you send resources)

当您知道须要为您的应用发送哪些资源以使其成为您想要的美观和功能时,请考虑下一步如何发送它们。与预见和预防同样,交付对于构建快速用户体验相当重要。

  • 迁移到HTTP / 2。 HTTP / 2解决了HTTP / 1.1中固有的许多性能问题,例如并发请求限制和缺乏头压缩。
  • 使用资源提示加快资源交付。 rel = preload是一个这样的资源提示,它容许在浏览器发现它们以前提早获取关键资源。这能够对页面呈现产生明显的积极影响,并在明智地使用时下降交互时间。 rel = preconnect是另外一个资源提示,能够掩盖为第三方域上托管的资源打开新链接的延迟。
  • 现代网站平均提供大量JavaScript和CSS。在HTTP / 1环境中将样式和脚本捆绑到大型捆绑包中很常见。这样作是由于大量请求对性能有害。如今再也不是HTTP / 2在场的状况,由于多个同时请求更便宜。考虑在webpack中使用代码拆分来限制下载的脚本数量,使其仅限于当前页面或视图所需的内容。将CSS分红较小的模板或特定于组件的文件,并仅包含可能使用它们的资源。

数据规模(Mind how much data you send)

经过一些关于哪些资源适合发送以及如何发送它们的想法,咱们将介绍一些限制发送数据的建议:

  1. 配置服务器以压缩资源。压缩会大大减小您发送给用户的数据量,尤为是在涉及文本资产的状况下。 GZIP在这个领域是一种很是优秀的格式,但Brotli压缩能够更进一步。可是,要理解压缩并非性能问题的所有:一些隐式压缩的文件格式(例如,JPEG,PNG,GIF,WOFF等)不响应压缩,由于它们已经被压缩。
  2. 优化图片以确保您的网站尽量少地发送图片数据。因为图片构成了网络上每页平均有效负载的很大一部分,所以图片优化表明了提高性能的独特机会。
  3. 客户端提示可用于根据当前网络条件和设备特征定制资源交付。 DPR,Width和Viewport-Width标头能够帮助您使用服务器端代码为设备提供最佳图像,并提供更少的标记。 Save-Data标头能够帮助您为明确要求您的用户提供更轻松的应用程序体验。
  4. NetworkInformation API公开有关用户网络链接的信息。此信息可用于修改较慢网络上的用户的应用程序体验。
  5. 减小请求(HTTP requests reduction)
  6. 文件压缩(File compression)
  7. 优化web缓存(Web caching optimization)

Web Caching Optimization reduces server load, bandwidth usage, and latency. CDNs use dedicated web caching software to store copies of documents passing through their system. Leveraging the browser cache is crucial. It is recommended to have a max-age of 7 days in such cases. This saves server time and makes things altogether faster.

  1. 简化代码(Code minification)
  2. 矢量图替换位图(Replacement of vector graphics)
  3. 避免301 重定向

Redirects are performance killers. Avoid them whenever possible. A redirect will generate additional round-trip times and therefore quickly doubles the time that is required to load the initial HTML document before the browser even starts to load other assets.

  1. 采用基于云的网站监控(Adopt Cloud-based Website Monitoring)

  2. 资源预加载:Pre-fetching是一种提示浏览器预先加载用户以后可能会使用到的资源的方法。

  • 使用dns-prefetch来提早进行DNS解析,以便以后能够快速地访问另外一个主机名(浏览器会在加载网页时对网页中的域名进行解析缓存,这样你在以后的访问时无需进行额外的DNS解析,减小了用户等待时间,提升了页面加载速度)。
<link rel="dns-prefetch" href="other.hostname.com">
复制代码
  • 使用prefetch属性能够预先下载资源,不过它的优先级是最低的。
<link rel="prefetch"  href="/some_other_resource.jpeg">
复制代码
  • Chrome容许使用subresource属性指定优先级最高的下载资源(当全部属性为subresource的资源下载完完毕后,才会开始下载属性为prefetch的资源)。
<link rel="subresource"  href="/some_other_resource.js">
复制代码
  • prerender能够预先渲染好页面并隐藏起来,以后打开这个页面会跳过渲染阶段直接呈如今用户面前(推荐对用户接下来必须访问的页面进行预渲染,不然得不偿失)。
<link rel="prerender"  href="//domain.com/next_page.html">
复制代码
  1. SSL certificate/ HTTPS

  2. 热连接保护(Hotlink protection) 限制HTTP引用,以防止他人将您的资源嵌入其余网站。 热连接保护将经过禁止其余网站显示您的图像来节省带宽。

  3. 基础设施(Infrastructure)

  4. 数据库优化(Database Optimization)

  5. 使用webworker

(前端)主流框架主流作法案例(见下一篇)

参考连接

相关文章
相关标签/搜索