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)