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
客户端:如在浏览器输入https://www.baidu.com/
,通过 DNS 解析,查到baidu.com
对应的 IP(不一样时间、地点对应的 IP 可能会不一样),浏览器向该 IP 发送 HTTP 请求。html
服务端:服务器接收到 HTTP 请求,经计算,返回 HTTP 请求前端
浏览器对请求的呈现。默认渲染引擎能够呈现html,xml及图片。(经过插件)也能够呈现其它数据,好比pdf等。 目前只考虑html和css方面。html5
content tree:在此,渲染引擎解析html文档并将元素转换成DOM节点。node
render tree:在此,渲染引擎解析style(外部css文件或内联style)并转换。react
这是一个渐进式过程. 为保证好的UED,渲染引擎尽早展示内容. 在开始构建并展示render树以前,它不会等全部html被解析。部份内容被解析并呈现,同时进程继续解析网络中不断请求到的其他内容。webpack
<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
<script>
浏览器默认:当执行script时解析html代码暂停。对于慢服务和重script的状况意味着webpage呈现将被延后。<script defer>
简而言之:推迟script执行直到html解析结束。该属性的好处就是DOM渲染友好,对于你的script。然而,并不是每一个浏览器支持该属性,故不要期望它!<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. 若是这样仍然无效,可关闭全部元素,直到能够添加元素为止,或者忽略该标记。
复制代码
和 HTML 不一样,CSS 是上下文无关的语法,可使用简介中描述的各类解析器进行解析。事实上,CSS 规范定义了 CSS 的词法和语法。
:遇到 <script>
文档的解析将中止,直到脚本执行完毕。若是脚本是外部的,那么解析过程会中止,直到从网络同步抓取资源完成后再继续。HTML5 增长了一个选项----“defer”,这样不会中止文档解析,而是等到解析结束才执行.
预解析 WebKit 和 Firefox 都进行了这项优化。**在执行脚本时,其余线程会解析文档的其他部分,找出并加载须要经过网络加载的其余资源。**经过这种方式,资源能够在并行链接上加载,从而提升整体速度。请注意,预解析器不会修改 DOM 树,而是将这项工做交由主解析器处理;预解析器只会解析外部资源(例如外部脚本、样式表和图片)的引用。
样式表: 理论上来讲,应用样式表不会更改 DOM 树,所以彷佛没有必要等待样式表并中止文档解析
render树构建: 在 DOM 树构建的同时,浏览器还会构建:render树---按照正确的顺序绘制内容。
render树和 DOM 树的关系:呈现器是和 DOM 元素相对应的,但并不是一一对应。非可视化的 DOM 元素不会插入呈现树中,例如“head”元素。若是元素的 display 属性值为“none”,那么也不会显示在呈现树中(可是 visibility 属性值为“hidden”的元素仍会显示)。
SQL 注入:输入时进行了恶意的 SQL 拼装,致使最后生成的 SQL 有问题。攻击方式低端,常出如今比较低端的系统。
XSS(Cross Site Scripting,跨站脚本攻击)
前端最多见的攻击方式,不少网站(如 阮一峰博客)都被 XSS 攻击过。
原理:经过某种方式(发布文章、发布评论等)将一段特定的 JS 代码隐蔽地输入进去。JS 代码一旦执行,那可就不受控制了,由于它跟网页原有的 JS 有一样的权限,例如能够获取 server 端数据、能够获取 cookie 等。因而,攻击就这样发生了。
预防:最根本的方式,用正则表达式进行转换处理,如:
< 替换为:<
> 替换为:>
& 替换为:&
‘ 替换为:'
” 替换为:"
复制代码
另外,还能够经过对 cookie控制,好比对敏感的 cookie 增长http-only
限制,让 JS 获取不到 cookie 的内容。
预防 :加入各个层级的权限验证,如涉及现金交易,必需要输入密码或者指纹才行等。
从新渲染,就须要从新生成布局和从新绘制。前者叫作"重排"(reflow),后者叫作"重绘"(repaint)。"重绘"不必定须要"重排","重排"必然致使"重绘"。重排和重绘会不断触发,这是不可避免的。可是,它们很是耗费资源,是致使网页性能低下的根本缘由。提升网页性能,就是要下降"重排"和"重绘"的频率和成本,尽可能少触发从新渲染。
标记名称 | 描述 |
---|---|
O(1) | 常数:无论有多少值,执行时间恒定,通常表示简单值和存储在变量中的值(数组元素访问) |
O(logn) | 对数:执行总时间与数量相关,但要完成算法并不必定获取每一个值。如二分查找 |
O(n) | 线性:执行总时间和数量直接相关。如遍历操做 |
O(n2) | 平方:执行总时间与数量有关,每一个值至少要获取n次。如插入排序 |
// 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
复制代码
// 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
复制代码
// 多个变量声明
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个语句建立和初始化对象)
复制代码
// 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 "
*/
复制代码
// 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
复制代码
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
后缀。
<script src="https://cdn.bootcss.com/zepto/1.0rc1/zepto.min.js"></script>
复制代码
因为事件频繁被触发,于是频繁执行DOM操做、资源加载等重行为,致使UI停顿甚至浏览器崩溃。
什么时候考虑节流?
具体作法:
// 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)
})
复制代码
构建高性能应用程序的有效方法是审核发送给用户的资源。虽然Chrome开发人员工具中的网络面板能够很好地总结给定页面上使用的全部资源,但若是您到目前为止还没有考虑性能,那么知道从哪里开始可能会使人生畏。如下是一些建议:
若是您使用Bootstrap或Foundation来构建UI,请问本身是否有必要。这些抽象添加了浏览器必须下载,解析和应用于页面的大量CSS,全部这些都是在特定于站点的CSS进入图片以前。 Flexbox和Grid在使用相对较少的代码建立简单和复杂布局方面很是出色。因为CSS是一种render阻塞资源,所以CSS框架的开销可能会显着延迟渲染。您应该经过消除没必要要的开销来寻求加速渲染,而非尽量依赖于浏览器中的工具。
JavaScript库很方便,但并不老是必要的。以jQuery为例:因为querySelector
和querySelectorAll
等方法,元素选择获得了极大的简化。使用addEventListener
能够轻松进行事件绑定。classList,setAttribute
和getAttribute
提供了使用类和元素属性的简便方法。若是你必须使用类库,研究更精简的替代品。例如,Zepto是一个较小的jQuery替代品,Preact是React的一个小得多的替代品。
并不是全部网站都须要是单页面应用程序(SPA),由于它们常常普遍使用JavaScript。 JavaScript是咱们在字节的web字节上提供的最昂贵的资源,由于它不只必须下载,还必须解析,编译和执行。例如,具备优化前端架构的新闻和博客站点能够像传统的多页体验同样表现良好。
当您知道须要为您的应用发送哪些资源以使其成为您想要的美观和功能时,请考虑下一步如何发送它们。与预见和预防同样,交付对于构建快速用户体验相当重要。
经过一些关于哪些资源适合发送以及如何发送它们的想法,咱们将介绍一些限制发送数据的建议:
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.
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.
采用基于云的网站监控(Adopt Cloud-based Website Monitoring)
资源预加载:Pre-fetching是一种提示浏览器预先加载用户以后可能会使用到的资源的方法。
<link rel="dns-prefetch" href="other.hostname.com">
复制代码
<link rel="prefetch" href="/some_other_resource.jpeg">
复制代码
<link rel="subresource" href="/some_other_resource.js">
复制代码
<link rel="prerender" href="//domain.com/next_page.html">
复制代码
SSL certificate/ HTTPS
热连接保护(Hotlink protection) 限制HTTP引用,以防止他人将您的资源嵌入其余网站。 热连接保护将经过禁止其余网站显示您的图像来节省带宽。
基础设施(Infrastructure)
数据库优化(Database Optimization)