溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

一篇文章搞定前端面試

發(fā)布時(shí)間:2020-07-23 12:49:17 來(lái)源:網(wǎng)絡(luò) 閱讀:368 作者:jaybril 欄目:web開(kāi)發(fā)

本文旨在用最通俗的語(yǔ)言講述最枯燥的基本知識(shí)

面試過(guò)前端的老鐵都知道,對(duì)于前端,面試官喜歡一開(kāi)始先問(wèn)些HTML5新增元素啊特性啊,或者是js閉包啊原型啊,或者是css垂直水平居中怎么實(shí)現(xiàn)啊之類的基礎(chǔ)問(wèn)題,當(dāng)你能倒背如流的回答這些之后,面試官臉上會(huì)劃過(guò)一絲詭異的笑容,然后晴轉(zhuǎn)多云,故作深沉的清一下嗓子問(wèn):從用戶輸入U(xiǎn)RL到瀏覽器呈現(xiàn)頁(yè)面經(jīng)過(guò)了哪些過(guò)程?如果你懂,巴拉巴拉回答了一堆,他又接著問(wèn):那網(wǎng)頁(yè)具體是如何渲染出來(lái)的呢?如果你還懂,又巴拉巴拉的回答了一堆,他還會(huì)繼續(xù)問(wèn):那你有哪些網(wǎng)頁(yè)性能優(yōu)化的經(jīng)驗(yàn)?zāi)兀?/strong>當(dāng)你還能巴拉巴拉的回答了一堆之后,面試官這下心里就有逼數(shù)了,轉(zhuǎn)而去問(wèn)你一些和技術(shù)無(wú)關(guān)的七大姑八大姨之類的事情,這時(shí)候,你就可以歡呼你的offer基本已經(jīng)到手了。

那么各位問(wèn)題來(lái)了,真正輪到你去面試的時(shí)候
你能否很好的回到這些問(wèn)題呢?

  1. 用戶輸入U(xiǎn)RL回車之后,瀏覽器到底做了啥?
  2. 頁(yè)面渲染的完整流程是怎樣的?
  3. 前端性能優(yōu)化有哪些經(jīng)驗(yàn)?

如果不能,那我們往下走:
(有人會(huì)疑惑說(shuō)不是講前端嗎?為毛要講TCP、DNS這些與前端無(wú)關(guān)的知識(shí)?別慌咯,跟著文章走吧,多學(xué)無(wú)害?。?/strong>

文章提綱:

  1. TCP
  2. UDP
  3. 套接字socket
  4. HTTP協(xié)議
  5. DNS解析
  6. HTTP請(qǐng)求發(fā)起和響應(yīng)
  7. 頁(yè)面渲染的過(guò)程
  8. 頁(yè)面的性能優(yōu)化

TCP連接

TCP:Transmission Control Protocol, 傳輸控制協(xié)議,是一種面向連接的、可靠的、基于字節(jié)流的傳輸層通信協(xié)議。
說(shuō)的這么專業(yè),有啥用呢?
先來(lái)舉個(gè)栗子吧
還記得小時(shí)候我們做的紙杯電話么??jī)蓚€(gè)紙杯用一條繩子連到一起,兩個(gè)各拿一個(gè)紙杯把線拉直,一個(gè)對(duì)著紙杯講,一個(gè)用耳朵對(duì)著紙杯聽(tīng)。

一篇文章搞定前端面試

這其實(shí)就是一種最簡(jiǎn)單的連接通信,兩人通過(guò)一根線連接起來(lái),聲音從這邊的紙杯發(fā)出通過(guò)線傳輸?shù)搅硪粋€(gè)紙杯接收,擴(kuò)展到現(xiàn)在家家戶戶都有的固定電話也是如此,它的通信也是建立在雙方可接受并且信任的基礎(chǔ)上進(jìn)行,如:

  1. A拿起電話,撥通0775-6532122,開(kāi)始呼叫B
  2. B聽(tīng)到電話聲響起,拿起電話,此時(shí)A收到B已經(jīng)拿起電話的聲音
  3. 雙方開(kāi)始講話。

回到我們的tcp協(xié)議,其實(shí)它和上面所說(shuō)的電話協(xié)議差不多,只不過(guò)電話的協(xié)議是服務(wù)于電話通信,而tcp是服務(wù)于網(wǎng)絡(luò)通訊的一種協(xié)議,類似的,通訊雙方建立一次tcp連接,也需要經(jīng)過(guò)三個(gè)步驟(握手)。

  1. 客戶端發(fā)送syn包(syn=j)到服務(wù)器,并進(jìn)入SYN_SEND狀態(tài),等待服務(wù)器確認(rèn)。
  2. 服務(wù)器收到syn包,必須確認(rèn)客戶的SYN(ack=j+1),同時(shí)自己也發(fā)送一個(gè)SYN包(syn=k),即SYN+ACK包,此時(shí)服務(wù)器進(jìn)入SYN_RECV狀態(tài)。
  3. 客戶端收到服務(wù)器的SYN+ACK包,向服務(wù)器發(fā)送確認(rèn)包ACK(ack=k+1),此包發(fā)送完畢,客戶端和服務(wù)器進(jìn)入ESTABLISHED狀態(tài),完成三次握手。

<img src="https://jaybril.oss-cn-shenzhen.aliyuncs.com/wchat/tcp%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B.png">

上面幾個(gè)唧唧歪歪的英文看的有點(diǎn)懵逼,翻譯一下吧:
(大家最好記一下這些狀態(tài)碼,在服務(wù)器連接數(shù)的性能優(yōu)化中會(huì)經(jīng)常用到)

SYN:synchronous 建立聯(lián)機(jī)
ACK:acknowledgement 確認(rèn)
SYN_SENT:請(qǐng)求連接
SYN_RECV:服務(wù)端被動(dòng)打開(kāi)后,接收到了客戶端的SYN并且發(fā)送了ACK時(shí)的狀態(tài)。再進(jìn)一步接收到客戶端的ACK就進(jìn)入ESTABLISHED狀態(tài)。

值得注意的是:tcp在握手過(guò)程中并不攜帶數(shù)據(jù),(就像你打電話給酒店訂房時(shí),在確認(rèn)對(duì)方是酒店客服人員之前,你也不會(huì)馬上把×××號(hào)碼報(bào)給他吧?),而是在三次握手完成之后,才會(huì)進(jìn)行數(shù)據(jù)傳送

至于它的應(yīng)用場(chǎng)景,其實(shí)是根據(jù)它本身的特點(diǎn)而定的,比如對(duì)網(wǎng)絡(luò)通訊質(zhì)量有要求,需要保證數(shù)據(jù)準(zhǔn)確性時(shí),就需要用到TCP協(xié)議了,如HTTP、ftp等文件傳輸協(xié)議、或一些郵件傳輸協(xié)議(SMTP、pop等)

UDP協(xié)議

(UDP協(xié)議并非本文需要重點(diǎn)著筆的內(nèi)容,但是講到TCP了,作為他的互補(bǔ)兄弟,在此掠過(guò)一筆)

UDP :User Datagram Protocol 用戶數(shù)據(jù)報(bào)協(xié)議
相比于TCP的面向連接需要反復(fù)確認(rèn)的繁瑣步驟,UDP是一中性格特立獨(dú)行并且主觀性超強(qiáng)的非面向連接的協(xié)議,使用udp協(xié)議經(jīng)常通信并不需要建立連接,它只是負(fù)責(zé)把數(shù)據(jù)盡可能快的發(fā)送出去,簡(jiǎn)單粗暴,并且不可靠,而在接收端,UDP把每個(gè)消息斷放入隊(duì)列中,接收端程序從隊(duì)列中讀取數(shù)據(jù)。

有人會(huì)說(shuō),UDP協(xié)議這么不可靠,為啥還會(huì)造出來(lái)呢?
話說(shuō)回來(lái),天底下沒(méi)有無(wú)用之人,只有你不懂用的人而已,雖然UDP不可靠,但是它的傳輸速度快,效率高,在一些對(duì)數(shù)據(jù)準(zhǔn)確性要求不高的場(chǎng)景,UDP就變得很有用了,比如qq語(yǔ)音、qq視頻。

套接字socket

為什么要說(shuō)嵌套字?
那是因?yàn)榫拖袂懊嬲f(shuō)的,TCP或UDP都是一種協(xié)議,也就是計(jì)算機(jī)網(wǎng)絡(luò)通信中在傳輸層的一種協(xié)議,簡(jiǎn)單地說(shuō),就是一種約定,就像合作雙方的合同一樣,然后合同是死的,只有履行合同才是實(shí)質(zhì)性的行動(dòng),因此無(wú)論是TCP還是UDP要產(chǎn)生作用,都需要有實(shí)際的行為去執(zhí)行才能體現(xiàn)協(xié)議的作用,
那么,有什么辦法讓這些協(xié)議作用呢?
這就要說(shuō)到socket了。

socket:也叫嵌套字 ,是一組實(shí)現(xiàn)TCP/UDP通信的接口API,也就是說(shuō)無(wú)論TCP還是UDP,通過(guò)對(duì)scoket的編程,都可以實(shí)現(xiàn)TCP/UCP通信,作為一個(gè)通信鏈的句柄,它包含網(wǎng)絡(luò)通信必備的5種信息:

  1. 連接使用的協(xié)議
  2. 本地主機(jī)的IP地址
  3. 本地進(jìn)程的協(xié)議端口
  4. 遠(yuǎn)地主機(jī)的IP地址
  5. 遠(yuǎn)地進(jìn)程的協(xié)議端口

可見(jiàn),socket包含了通信本方和對(duì)方的ip和端口以及連接使用的協(xié)議(TCP/UDP)。通信雙方中的一方(暫稱:客戶端)通過(guò)scoket(嵌套字)對(duì)另一方(暫稱:服務(wù)端)發(fā)起連接請(qǐng)求,服務(wù)端在網(wǎng)絡(luò)上監(jiān)聽(tīng)請(qǐng)求,當(dāng)收到客戶端發(fā)來(lái)的請(qǐng)求之后,根據(jù)socket里攜帶的信息,定位到客戶端,就相應(yīng)請(qǐng)求,把socket描述發(fā)給客戶端,雙方確認(rèn)之后連接就建立了。
因此套接字之間的連接過(guò)程有三個(gè)步驟:

  1. 服務(wù)器監(jiān)聽(tīng):服務(wù)器實(shí)時(shí)監(jiān)控網(wǎng)絡(luò)狀態(tài)等待客戶端發(fā)來(lái)的連接請(qǐng)求
  2. 客戶端請(qǐng)求:客戶端根據(jù)遠(yuǎn)程主機(jī)服務(wù)器的IP地址和協(xié)議端口向其發(fā)起連接請(qǐng)求
  3. 連接確認(rèn):服務(wù)端收到套接字的連接請(qǐng)求之后,就響應(yīng)請(qǐng)求,把服務(wù)端套接字描述發(fā)給客戶端,客戶端收到后一旦確認(rèn),則雙方建立連接,進(jìn)行數(shù)據(jù)交互。

通常情況下socket連接就是TCP連接,因此socket連接一旦建立,通訊雙方開(kāi)始互發(fā)數(shù)據(jù)進(jìn)行通信,直到其中一方或雙方斷開(kāi)連接為止。

socket在即時(shí)通訊(qq等各種聊天軟件)等應(yīng)用上應(yīng)用廣泛。

HTTP協(xié)議

HTTP協(xié)議:Hypertext Transfer Protocol 也叫超文本傳送協(xié)議 ,它是一種基于TCP/IP協(xié)議棧、在表示層和應(yīng)用層上的協(xié)議(TCP在傳輸層的協(xié)議),通俗一點(diǎn)說(shuō)就是:

  • TCP/IP是位于傳輸層上的一種協(xié)議,用于在網(wǎng)絡(luò)中傳輸數(shù)據(jù);
  • HTTP協(xié)議是應(yīng)用層協(xié)議,基于TCP協(xié)議,用于包裝數(shù)據(jù),程序使用它進(jìn)行通信,可以簡(jiǎn)單高效的處理通信中數(shù)據(jù)的傳輸和識(shí)別處理

而在現(xiàn)在應(yīng)用非常廣泛的HTTP連接則是建立在HTTP協(xié)議上的、處于應(yīng)用層中的一種具體應(yīng)用。
上面說(shuō)到socket連接一旦建立就保持連接狀態(tài),而HTTP連接則不一樣,它基于tcp協(xié)議的短連接,也就是客戶端發(fā)起請(qǐng)求,服務(wù)器響應(yīng)請(qǐng)求之后,連接就會(huì)自動(dòng)斷開(kāi),不會(huì)一直保持。

URL

前面講了tcp、udp、http...等等都是為了講一個(gè)具體問(wèn)題而做的知識(shí)點(diǎn)鋪墊,那就是:我們開(kāi)發(fā)的web應(yīng)用中請(qǐng)求的發(fā)起和響應(yīng),是一個(gè)怎樣的底層原理。
我們都知道,web應(yīng)用絕大部分都是通過(guò)HTTP來(lái)進(jìn)行請(qǐng)求的,而URL則是HTTP用來(lái)做連接建立和傳輸數(shù)據(jù)的一種具體實(shí)現(xiàn),因此在此要簡(jiǎn)單講一下URL。

URL:Uniform Resource Locator 統(tǒng)一資源定位符。說(shuō)白了就是網(wǎng)絡(luò)上用來(lái)標(biāo)識(shí)具體資源的一個(gè)地址,包含了用戶查找該資源的信息,HTTP使用它來(lái)傳輸數(shù)據(jù)和建立連接
一個(gè)URL有以下組成部分:

  1. 協(xié)議
  2. 服務(wù)器地址(域名或IP+端口)
  3. 路徑
  4. 文件名

比如:https://www.baidu.com/index.html
其中

  1. https://是一種協(xié)議 當(dāng)然,HTTP也是 ftp也是...
  2. www.baidu.com是服務(wù)器地址,當(dāng)然你知道百度的IP也可以,例如我用ping命令得到百度的ip
    14.215.177.39,那么我可以用http://14.215.177.39打開(kāi)百度
  3. index.html包含了路徑和文件名,當(dāng)然通常index.html是可以省略的,所以你打開(kāi)百度時(shí),并沒(méi)有看到這個(gè)。

DNS

DNS:Domain Name Server,域名服務(wù)器。
是進(jìn)行域名(domain name)和與之相對(duì)應(yīng)的IP地址 (IP address)轉(zhuǎn)換的服務(wù)器。DNS中保存了一張域名(domain name)和與之相對(duì)應(yīng)的IP地址 (IP address)的表,以解析消息的域名。
在平時(shí)我們進(jìn)行開(kāi)發(fā)時(shí),后端提供的接口地址通常是有IP地址加上端口號(hào)(8080什么鬼的)組成的,但是當(dāng)我們把網(wǎng)站發(fā)布出去時(shí),通常都需要把IP改成用域名。
為什么呢?
你想想哦,比如谷歌的地址是89.12.21.221:9090,百度的地址是132.21.33.221:8766。。。
這么一看你根本沒(méi)有欲望是記住這些亂七八糟的數(shù)字吧?
但是域名就不一樣了,比如谷歌的google.com,百度的baidu.com 是不是一遍就記住了呢?
所以為了處理這個(gè)問(wèn)題,就需要用域名去映射IP地址,達(dá)到易記易用的目的。

因此,當(dāng)用戶在瀏覽器輸入https://www.baidu.com回車時(shí),它經(jīng)歷了以下步驟:

  1. 瀏覽器根據(jù)地址去本身緩存中查找dns解析記錄,如果有,則直接返回IP地址,否則瀏覽器會(huì)查找操作系統(tǒng)中(hosts文件)是否有該域名的dns解析記錄,如果有則返回。
  2. 如果瀏覽器緩存和操作系統(tǒng)hosts中均無(wú)該域名的dns解析記錄,或者已經(jīng)過(guò)期,此時(shí)就會(huì)向域名服務(wù)器發(fā)起請(qǐng)求來(lái)解析這個(gè)域名。
  3. 請(qǐng)求會(huì)先到LDNS(本地域名服務(wù)器),讓它來(lái)嘗試解析這個(gè)域名,如果LDNS也解析不了,則直接到根域名解析器請(qǐng)求解析
  4. 根域名服務(wù)器給LDNS返回一個(gè)所查詢余的主域名服務(wù)器(gTLDServer)地址。
  5. 此時(shí)LDNS再向上一步返回的gTLD服務(wù)器發(fā)起解析請(qǐng)求。
  6. gTLD服務(wù)器接收到解析請(qǐng)求后查找并返回此域名對(duì)應(yīng)的Name Server域名服務(wù)器的地址,這個(gè)Name Server通常就是你注冊(cè)的域名服務(wù)器(比如阿里dns、騰訊dns等)
  7. Name Server域名服務(wù)器會(huì)查詢存儲(chǔ)的域名和IP的映射關(guān)系表,正常情況下都根據(jù)域名得到目標(biāo)IP記錄,連同一個(gè)TTL值返回給DNS Server域名服務(wù)器
  8. 返回該域名對(duì)應(yīng)的IP和TTL值,Local DNS Server會(huì)緩存這個(gè)域名和IP的對(duì)應(yīng)關(guān)系,緩存的時(shí)間有TTL值控制。
  9. 把解析的結(jié)果返回給用戶,用戶根據(jù)TTL值緩存在本地系統(tǒng)緩存中,域名解析過(guò)程結(jié)束。

HTTP請(qǐng)求發(fā)起和響應(yīng)

如果這篇文章的主題是網(wǎng)絡(luò)通信,那到這里已經(jīng)可以告一段落了,但今天我們要講的是web應(yīng)用中請(qǐng)求的發(fā)起和響應(yīng)以及頁(yè)面渲染的原理,因此以上只是鋪墊。
在一個(gè)web程序開(kāi)發(fā)中,一般都有前端和后端之分,前端負(fù)責(zé)向后端請(qǐng)求數(shù)據(jù)和展示頁(yè)面,后端負(fù)責(zé)接收請(qǐng)求和做出響應(yīng)發(fā)回給前端,他們之間的協(xié)作的橋梁是什么呢?
是API
API是什么?不就是一個(gè)URL嗎?
URL又是啥呢?上面說(shuō)到就是HTTP連接的一種具體的載體
因此,
無(wú)論對(duì)于前端或者是后端,理解HTTP,無(wú)論是對(duì)自身對(duì)編程的理解,還是和同事協(xié)作,都是好處大大的,
下面,根據(jù)上面各個(gè)知識(shí)點(diǎn)的理解,我們來(lái)整理一下并解決一下上面提到的第一個(gè)問(wèn)題:
從用戶輸入U(xiǎn)RL,到瀏覽器呈現(xiàn)給用戶頁(yè)面,經(jīng)過(guò)了什么過(guò)程

  1. 用戶輸入U(xiǎn)RL,瀏覽器獲取到URL
  2. 瀏覽器(應(yīng)用層)進(jìn)行DNS解析(如果輸入的是IP地址,此步驟省略)
  3. 根據(jù)解析出的IP地址+端口,瀏覽器(應(yīng)用層)發(fā)起HTTP請(qǐng)求,請(qǐng)求中攜帶(請(qǐng)求頭header(也可細(xì)分為請(qǐng)求行和請(qǐng)求頭)、請(qǐng)求體body),

    header包含:

    1. 請(qǐng)求的方法(get、post、put..)
    2. 協(xié)議(http、https、ftp、sftp...)
    3. 目標(biāo)url(具體的請(qǐng)求路徑已經(jīng)文件名)
    4. 一些必要信息(緩存、cookie之類)

body包含:

  1. 請(qǐng)求的內(nèi)容
  1. 請(qǐng)求到達(dá)傳輸層,tcp協(xié)議為傳輸報(bào)文提供可靠的字節(jié)流傳輸服務(wù),它通過(guò)三次握手等手段來(lái)保證傳輸過(guò)程中的安全可靠。通過(guò)對(duì)大塊數(shù)據(jù)的分割成一個(gè)個(gè)報(bào)文段的方式提供給大量數(shù)據(jù)的便攜傳輸。
  2. 到網(wǎng)絡(luò)層, 網(wǎng)絡(luò)層通過(guò)ARP尋址得到接收方的Mac地址,IP協(xié)議把在傳輸層被分割成一個(gè)個(gè)數(shù)據(jù)包傳送接收方。
  3. 數(shù)據(jù)到達(dá)數(shù)據(jù)鏈路層,請(qǐng)求階段完成
  4. 接收方在數(shù)據(jù)鏈路層收到數(shù)據(jù)包之后,層層傳遞到應(yīng)用層,接收方應(yīng)用程序就獲得到請(qǐng)求報(bào)文。
  5. 接收方收到發(fā)送方的HTTP請(qǐng)求之后,進(jìn)行請(qǐng)求文件資源(如HTML頁(yè)面)的尋找并響應(yīng)報(bào)文
  6. 發(fā)送方收到響應(yīng)報(bào)文后,如果報(bào)文中的狀態(tài)碼表示請(qǐng)求成功,則接受返回的資源(如HTML文件),進(jìn)行頁(yè)面渲染。

頁(yè)面的渲染

當(dāng)一個(gè)請(qǐng)求的發(fā)起和響應(yīng)都完成之后,瀏覽器就會(huì)收到響應(yīng)內(nèi)容,但瀏覽器收到的是一串串的代碼或URL鏈接,怎么把這些代碼轉(zhuǎn)化成用戶可以看得懂的界面呈現(xiàn)出來(lái),就是瀏覽器的工作了。
目前市場(chǎng)上的瀏覽器已經(jīng)不下百種,各個(gè)瀏覽器根據(jù)內(nèi)核又可以分成幾大類,每一類瀏覽器對(duì)頁(yè)面的渲染原理和過(guò)程有所差異。

但總的來(lái)說(shuō),各個(gè)瀏覽器渲染頁(yè)面都基本遵循如下圖的流程:
一篇文章搞定前端面試

圖中有幾處英文詞匯可能不好理解,沒(méi)關(guān)系,先做一下解釋:

  1. HTML parser:HTML解析器,其本質(zhì)是將HTML文本解釋成DOM tree。
  2. CSS parser:CSS解析器,其本質(zhì)是講DOM中各元素對(duì)象加入樣式信息
  3. JavaScript引擎:專門處理JavaScript腳本的虛擬機(jī),其本質(zhì)是解析JS代碼并且把邏輯(HTML和CSS的操作)應(yīng)用到布局中,從而按程序要的要求呈現(xiàn)相應(yīng)的結(jié)果
  4. DOM tree:文檔對(duì)象模型樹(shù),也就是瀏覽器通過(guò)HTMLparser解析HTML頁(yè)面生成的HTML樹(shù)狀結(jié)構(gòu)以及相應(yīng)的接口。
  5. render tree:渲染樹(shù),也就是瀏覽器引擎通過(guò)DOM Tree和CSS Rule Tree構(gòu)建出來(lái)的一個(gè)樹(shù)狀結(jié)構(gòu),和dom tree不一樣的是,它只有要最終呈現(xiàn)出來(lái)的內(nèi)容,像<head>或者帶有display:none的節(jié)點(diǎn)是不存在render tree中的。
  6. layout:也叫reflow 重排,渲染中的一種行為。當(dāng)rendertree中任一節(jié)點(diǎn)的幾何尺寸發(fā)生改變了,render tree都會(huì)重新布局。
  7. repaint:重繪,渲染中的一種行為。render tree中任一元素樣式屬性(幾何尺寸沒(méi)改變)發(fā)生改變了,render tree都會(huì)重新畫(huà),比如字體顏色、背景等變化。

所以,根據(jù)關(guān)鍵詞匯的解釋以及順著流程圖的流程,可以總結(jié)出,瀏覽器解析渲染頁(yè)面主要包括以下過(guò)程:

  1. 瀏覽器通過(guò)HTMLParser根據(jù)深度遍歷的原則把HTML解析成DOM Tree。
  2. 將CSS解析成CSS Rule Tree(CSSOM Tree)。
  3. 根據(jù)DOM樹(shù)和CSSOM樹(shù)來(lái)構(gòu)造render Tree。
  4. layout:根據(jù)得到的render tree來(lái)計(jì)算所有節(jié)點(diǎn)在屏幕的位置。
  5. paint:遍歷render樹(shù),并調(diào)用硬件圖形API來(lái)繪制每個(gè)節(jié)點(diǎn)。

前端性能優(yōu)化

對(duì)于頁(yè)面渲染基本上這樣就是一個(gè)的流程,看完之后,有沒(méi)有什么感覺(jué)在實(shí)際編碼中可以優(yōu)化的點(diǎn)呢?沒(méi)有吧?因?yàn)楹芏嗉?xì)節(jié)都沒(méi)有講述,因此為了找到可優(yōu)化的點(diǎn),在此對(duì)頁(yè)面渲染過(guò)程的幾個(gè)關(guān)鍵步驟做一下陳述:

1. HTML解析:

上面講到,HTML解析是瀏覽器的HTML解析器把HTML解析成dom tree,而在解析過(guò)程,瀏覽器根據(jù)HTML文件的結(jié)構(gòu)從上到下解析html,HTML元素是以深度優(yōu)先的方式解析,而script、link、style等標(biāo)簽會(huì)使解析過(guò)程產(chǎn)生阻塞,阻塞的情況有:

  1. 外部樣式會(huì)阻塞內(nèi)部腳本的執(zhí)行。
  2. 外部樣式與外部腳本并行加載,但外部樣式會(huì)阻塞外部腳本執(zhí)行。
  3. 如果外部腳本帶有async屬性,則外部腳本的加載與執(zhí)行不受外部樣式影響
  4. 如果link標(biāo)簽是動(dòng)態(tài)創(chuàng)建(js生成),不管有無(wú)async屬性,都不會(huì)阻塞外部腳本的加載與執(zhí)行。
2. CSS解析:

CSS Parser作用就是將很多個(gè)CSS文件中的樣式合并解析出具有樹(shù)形結(jié)構(gòu)Style Rules,在對(duì)樣式解析的過(guò)程中,默認(rèn)CSS選擇器是從右往左進(jìn)行解析的。至于為什么是從右到左,而不是從左到右、也是不會(huì)從左到左...
下面舉個(gè)栗子來(lái)說(shuō)一下:
假如現(xiàn)在有這樣的一個(gè)樣式:

#parent .ch2 .dh2 {}
.fh2 .ch2 .dh2{}
.ah2 .ch2 .eh2 {}
#parent .fh2 {}
.ch2 .dh2{}

我們來(lái)比較從左到右和從右到左兩種方式的結(jié)果:
一篇文章搞定前端面試
從兩個(gè)圖的比較就可以看幾點(diǎn):

  1. 右邊的tree復(fù)雜度要比左邊的低
  2. 右邊的tree公用樣式重合度比左邊的低
  3. 右邊的tree從根開(kāi)始的節(jié)點(diǎn)數(shù)要比左邊的少

可能光看這幾點(diǎn)沒(méi)看出什么問(wèn)題,但你要知道:瀏覽器中的css解析器負(fù)責(zé)css的解析,并為每個(gè)節(jié)點(diǎn)計(jì)算出樣式,因此雖然css解析器要做的事情不多,但要每個(gè)節(jié)點(diǎn)都要進(jìn)行遍歷查找計(jì)算,計(jì)算量極大,因此解析的方式是決定其性能的關(guān)鍵點(diǎn)。
就如

#parant .a{}
和
.a{}

估計(jì)絕大多數(shù)人都會(huì)認(rèn)為前者要比后者性能更優(yōu),其實(shí)不然,在解析過(guò)程中
#paran .a{}意味著css解析器要先找到#parent再找到他下面的.a所在節(jié)點(diǎn)
而后者可以直接定位到.a{}因此哪一種方式更優(yōu),顯而易見(jiàn)。

3. 腳本執(zhí)行:

瀏覽器解析HTML時(shí),當(dāng)遇到\<script>標(biāo)簽就會(huì)立即解析腳本,同時(shí)阻塞解析文檔直到腳本執(zhí)行完畢(你可能問(wèn)為什么要這樣設(shè)計(jì),明顯啊,腳本的執(zhí)行是改變css和dom,會(huì)造成render tree不停的重繪和重排的),而當(dāng)\<script>是引入外部js文件時(shí),會(huì)阻塞到j(luò)s文件下載完成并且執(zhí)行完成為止(除非加了defer或者async屬性)。腳本在解析過(guò)程中將對(duì)dom或css的操作解析出來(lái)加入到DOM Tree和cssom中。


性能優(yōu)化

把這些度講完之后,對(duì)于性能優(yōu)化的點(diǎn),相信大家心里都有點(diǎn)X數(shù)了吧,下面簡(jiǎn)單總結(jié)一下日常開(kāi)發(fā)過(guò)程中常用的性能優(yōu)化的地方:

1.對(duì)于css:
  1. 優(yōu)化選擇器路徑:健全的css選擇器固然是能讓開(kāi)發(fā)看起來(lái)更清晰,然后對(duì)于css的解析來(lái)說(shuō)卻是個(gè)很大的性能問(wèn)題,因此相比于 .a .b .c{} ,更傾向于大家寫(xiě).c{}。
  2. 壓縮文件:盡可能的壓縮你的css文件大小,減少資源下載的負(fù)擔(dān)。
  3. 選擇器合并:把有共同的屬性內(nèi)容的一系列選擇器組合到一起,能壓縮空間和資源開(kāi)銷
  4. 精準(zhǔn)樣式:盡可能減少不必要的屬性設(shè)置,比如你只要設(shè)置{padding-left:10px}的值,那就避免{padding:0 0 0 10px}這樣的寫(xiě)法
  5. 雪碧圖:在合理的地方把一些小的圖標(biāo)合并到一張圖中,這樣所有的圖片只需要一次請(qǐng)求,然后通過(guò)定位的方式獲取相應(yīng)的圖標(biāo),這樣能避免一個(gè)圖標(biāo)一次請(qǐng)求的資源浪費(fèi)。
  6. 避免通配符:.a .b *{} 像這樣的選擇器,根據(jù)從右到左的解析順序在解析過(guò)程中遇到通配符(*)回去遍歷整個(gè)dom的,這樣性能問(wèn)題就大大的了。
  7. 少用Float:Float在渲染時(shí)計(jì)算量比較大,盡量減少使用。
  8. 0值去單位:對(duì)于為0的值,盡量不要加單位,增加兼容性
2.對(duì)于JavaScript:
  1. 盡可能把script標(biāo)簽放到body之后,避免頁(yè)面需要等待js執(zhí)行完成之后dom才能繼續(xù)執(zhí)行,最大程度保證頁(yè)面盡快的展示出來(lái)。
  2. 盡可能合并script代碼,
  3. css能干的事情,盡量不要用JavaScript來(lái)干。畢竟JavaScript的解析執(zhí)行過(guò)于直接和粗暴,而css效率更高。
  4. 盡可能壓縮的js文件,減少資源下載的負(fù)擔(dān)
  5. 盡可能避免在js中逐條操作dom樣式,盡可能預(yù)定義好css樣式,然后通過(guò)改變樣式名來(lái)修改dom樣式,這樣集中式的操作能減少reflow或repaint的次數(shù)。
  6. 盡可能少的在js中創(chuàng)建dom,而是預(yù)先埋到HTML中用display:none來(lái)隱藏,在js中按需調(diào)用,減少js對(duì)dom的暴力操作。
3. 對(duì)于HTML:
  1. 避免再HTML中直接寫(xiě)css代碼。
  2. 使用Viewport加速頁(yè)面的渲染。
  3. 使用語(yǔ)義化標(biāo)簽,減少css的代碼,增加可讀性和SEO。
  4. 減少標(biāo)簽的使用,dom解析是一個(gè)大量遍歷的過(guò)程,減少無(wú)必要的標(biāo)簽,能降低遍歷的次數(shù)。
  5. 避免src、href等的值為空。
  6. 減少dns查詢的次數(shù)。

以上就是文章的所有內(nèi)容,總的來(lái)說(shuō),入門的文章是領(lǐng)人入門,進(jìn)階的文章帶人進(jìn)階,就像Java的書(shū)會(huì)有入門教程和進(jìn)階教程一樣,這個(gè)文章里邊寫(xiě)的大部分知識(shí)點(diǎn)都是為了讓讀者對(duì)頁(yè)面請(qǐng)求和呈現(xiàn)有一個(gè)鋪墊和整體的認(rèn)知,由于涉及的知識(shí)點(diǎn)過(guò)多,每個(gè)知識(shí)點(diǎn)拎出來(lái)都可以寫(xiě)一本書(shū),所以大家把本文作為一個(gè)引路文,需要對(duì)某個(gè)知識(shí)點(diǎn)進(jìn)行深入研究時(shí)再找相關(guān)書(shū)籍研究,不喜勿噴。


覺(jué)得本文對(duì)你有幫助?請(qǐng)分享給更多人
關(guān)注「編程×××」,提升裝逼技能
<br>一篇文章搞定前端面試

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI