從輸入`URL`到頁面加載完成的過程當中都發生了什麼事情

概覽

日期:2018-4-26
目的:相識從輸入URL到頁面加載完成的歷程當中都發作了什麼事情
總用時:一天
完成狀況:殺青

基本歷程

為何會想要相識從輸入URL到頁面加載完成的歷程當中都發作了什麼事情這個題目呢,因為課程參考資料的Web 建站手藝中HTML、HTML5、XHTML、CSS、SQL、JavaScript、PHP、ASP.NET、Web Services 是什麼中最高票答案中給出了下圖所示的網站接見基本歷程,張秋怡學姐的解答也異常易懂:

《從輸入`URL`到頁面加載完成的過程當中都發生了什麼事情》

再者這個題目可謂是罕見的面試題之一,而這張圖中只是給出了異常基本的一個前後端交互的歷程,因為本身有基本,所以列出的相干看法也都基本理解了,因而就花些時刻擴大一下

跟我一起來學起來

  • 我們在翻開瀏覽器,然後在輸入URL的時刻有無發明瀏覽器會給你一些你素昧平生且與你輸入的內容相婚配的網址呢?

    《從輸入`URL`到頁面加載完成的過程當中都發生了什麼事情》

    實在我們在瀏覽器中輸入URL的時刻,瀏覽器就會最先智能的婚配能夠URL,瀏覽器會從歷史記錄,書籤等處所,找到你已輸入的字符串能夠對應的URL,然後給出智能提醒

  • 在輸好URL后我們會按下Enter鍵,瀏覽器會提議請求,假如URL是域名而不是IP地點,將舉行域名剖析,所謂域名剖析是指什麼呢?

    IP地點是收集上標識站點的数字地點,為了
    輕易影象,採納域名來替代
    IP地點標識站點地點,域名剖析就是域名到
    IP地點的轉換歷程。

    域名剖析按下面的步驟舉行(部份內容觸及到計算機收集學問):

    • 我們當地硬盤下有一個hosts(windows下途徑為C:\Windows\System32\drivers\etc)文件,作用是將一些經常運用的網址域名與其對應的IP地點豎立一個關聯“數據庫”。平常來講,體系會起首自動從hosts文件中尋覓對應的IP地點,假若有的話就直接運用hosts文件內里的IP地點,然後直接舉行端口確認
    • 假如上一步沒有找到,瀏覽器將挪用剖析遞次,並成為DNS效勞器的一個客戶,把待剖析的域名放在DNS請求報文中,以UDP用戶數據報的體式格局發給當地DNS效勞器
    • 假如當地DNS效勞器查找到相應的域名的IP地點,就把對應的IP地點放在回覆報文中返回
    • 假如上一步沒有找到,即當地DNS效勞器不曉得被查詢域名的IP地點,因為主機向當地DNS效勞器的查詢是遞歸查詢,所以此時,當地DNS效勞器就會以DNS客戶的身份向其他DNS效勞器繼承發出查詢請求報文。當地DNS效勞器向根DNS效勞器的查詢是迭代查詢,當找到相應域名的IP地點后,就會把這個效果返回給最初提議查詢請求的瀏覽器

      遞歸查詢:在該形式下
      DNS效勞器吸收到客戶機請求,必需返回一個正確的查詢效果給客戶機。假如該
      DNS效勞器當地沒有存儲被查詢的
      DNS信息,那末該效勞器會(替客戶機)訊問其他效勞器,並將返回的查詢效果再返回給客戶機。

      迭代查詢:在該形式下
      DNS效勞器吸收到客戶機請求,假如該
      DNS效勞器當地沒有存儲被查詢的
      DNS信息,
      DNS效勞器會向客戶機供應其他能夠剖析查詢請求的
      DNS效勞器地點,讓客戶機再向這台
      DNS效勞器提交請求,順次輪迴直到返回查詢的效果為止。

    • 經由上面的步驟后,瀏覽器已取得輸入域名的IP地點,能夠舉行下一步了。
  • 瀏覽器獲得IP地點后,還要確認一下端口,默許端口是80端口,一個效勞器能夠會供應差別的效勞,這些效勞經由過程端口來辨別,能夠指定端口號
  • 瀏覽器獲得IP地點並確認端口后,會向目的效勞器提議HTTP請求,HTTP請求是經由過程TCP銜接來發送的(假如是HTTPS則須要先豎立SSL銜接,再是TCP銜接,下面的議論基於HTTP),詳細以下

    • 瀏覽器會天生目的效勞器的HTTP請求報文,請求報文平常包括請求要領、請求URI、協定版本、請求首部字段等內容,HTTP請求預備好后,HTTP請求報文從應用層傳到傳輸層後會被支解為報文段,並會提議一條抵達目的效勞器的TCP銜接,最先TCP三次握手,歷程如圖所示:

      《從輸入`URL`到頁面加載完成的過程當中都發生了什麼事情》

      淺顯的能夠理解為:

      A主意向B打電話:嗨,能聽到嗎(SYN=1,seq=x),然後A就最先守候B的回覆(SYN-SENT狀況),此時A不曉得B能不能聽到

      B聽到A的話今後,能夠確認它能聽到A,然則它還要確認一下A能不能聽到他本身的聲響,因而B說:我能聽到你的聲響(ACK=1,ack=x+1),你能聽到我的聲響嗎(SYN=1,seq=y),然後B最先守候A的恢復(SYN-RECD狀況)

      A聽到B的話今後,A能夠確認兩件事,一是B能聽到它措辭,二是它也能聽到B措辭,A已能夠隨時措辭和傾聽了(ESTABLISHED狀況)。然則此時的B還在守候中,並不曉得A能不能聽到,所以此時A須要再復興B說:我能夠聽到你的聲響(ACK=1,ack=y+1),最先興奮的談天吧~(seq=x+1),B聽到這句話后便也能夠隨時措辭和傾聽了(ESTABLISHED狀況)

      今後兩個人就能夠balabalabala….

    • HTTP請求的請求報文是直接附在第三次握手的音訊中
    • 交叉補充小學問,為何是三次握手,而不是兩次四次?

      有一種看法是三次握手是基於
      TCP協定的牢靠性(
      Reliability)請求,這是確認雙發都能舉行收發的最小次數,兩次確認不了,四次過剩。然則並沒有完全意義上的牢靠,不管握手多少次都只能表明握手的時刻是牢靠的,不能保證背面數據傳輸時一向牢靠,因為
      信道是不牢靠的,固然三次握手最少能夠表明它曾牢靠,這是兩次握手沒法完成的,而四次以至更屢次握手僅僅是進步“它曾牢靠”這個結論的可托水平。所以這個握手也只是確保牢靠的一個基本須要,
      TCP協定的牢靠性(注重辨別完全性
      integrity)更多的是由校驗和、定時器超時重傳、確認機制

      在《計算機收集》一書中也有講過這個題目,給出的詮釋是:三次握手是為了防備失效的銜接請求報文段被效勞端吸收,從而發作毛病。詳細例子以下所述:
      client發出的一個銜接請求報文段並沒有喪失,而是在某個收集結點長時刻的滯留了,致使耽擱到銜接開釋今後的某個時刻才抵達server。原本這是一個早已失效的報文段。但server收到此失效的銜接請求報文段后,就誤認為是client再次發出的一個的銜接請求。因而就向client發出確認報文段,贊同豎立銜接。
      假定不採納“三次握手”,那末只需server發出確認,新的銜接就豎立了。然則因為如今client並沒有發出豎立銜接的請求,因而不會剖析server的確認,也不會向server發送數據。而server卻認為新的銜接已豎立,並一向守候client發來數據。如許,server的許多資本就白白浪費掉了。
      採納“三次握手”的方法能夠防備上述徵象發作。比方適才那種狀況,client不會向server的確認發出確認。server因為收不到確認,就曉得client並沒有請求豎立銜接

  • 銜接豎立今後,最先舉行數據傳輸,雖然瀏覽器曉得目的效勞器的IP和端口,然則數據總不能夠飛過去吧?HTTP請求報文段會從傳輸層傳到收集層,在收集層被封裝成IP數據包,收集層劃定了經由過程怎樣的途徑(所謂的傳輸線路)抵達目的效勞器,並把數據包傳送給對方。
  • 收集層封裝好的IP數據包會進一步傳到下一層 — 數據鏈路層,然後會再次被封裝到MAC數據幀構造中,因為IP地點間的通訊依靠於MAC地點(網卡所屬的牢固地點),所以MAC數據幀構造中會有經由ARP協定剖析后的MAC地點(不肯定是目的效勞器的MAC地點,因為實際上通訊的兩邊在統一局域網(LAN)內的狀況是很少的,平常都邑經由路由中轉)。
  • 數據鏈路層的MAC數據幀再向下傳,便會抵達物理層,這裏要注重物理層斟酌的是怎樣才在銜接種種計算機的傳輸媒體上傳輸數據比特流,而不是指詳細的傳輸媒體。 物理層須要確保原始的數據可在種種物理媒體上傳輸,它劃定了傳輸媒體的機器特徵、電氣特徵、功用特徵、歷程特徵:

    《從輸入`URL`到頁面加載完成的過程當中都發生了什麼事情》

    罕見的傳輸媒體有雙絞線、電纜、光纜、無線信道等,物理層的使命就是要讓數據在這些傳輸媒體上都能能舉行傳輸

  • 經由過程MAC地點婚配,數據經由過程傳輸媒體抵達目的效勞器的物理層,物理層吸收數據比特流然後向上傳送到效勞器的數據鏈路層,在數據鏈路層MAC數據幀將舉行封裝的逆操縱,還原成IP數據包今後向上傳送到收集層,收集層也舉行封裝的逆操縱還原成HTTP請求報文段(支解后的一小段一小段的),然後這些報文段向上傳到傳輸層,在傳輸層按本來的序號從新組裝成完全的HTTP請求報文,再向上傳到應用層,應用層的HTTP協定便會最先對請求舉行處置懲罰
  • 這個處置懲罰多是直接返回靜態的資本,也能夠經由PHPJAVA等言語舉行處置懲罰等,等處置懲罰完成后,會返回一個HTTP相應,它天生一個HTTP相應報文,與HTTP請求報文構造相似,然後這個相應報文會“走過”請求報文來時的路抵達瀏覽器
  • 瀏覽器吸收HTTP相應,然後有能夠開釋TCP銜接,也有能夠從新運用這個TCP銜接發送新的請求(耐久銜接),此處相識一下TCP銜接的開釋,差別於TCP銜接豎立的三次握手,TCP銜接的開釋是四次揮手,客戶端和效勞器端都能夠提議封閉請求,也存在二者同時提議封閉請求的狀況,圖中為客戶端A主動提議封閉請求:

    《從輸入`URL`到頁面加載完成的過程當中都發生了什麼事情》

    一樣淺顯的詮釋一波:

    A對B要傳的文件已傳完了,因而他對B說:我要傳的文件已傳完了,我要預備下線了(seq=u,FIN=1)。然後A就守候B的復興(FIN-WAIT-1狀況)

    B看到A的音訊后,復興A說:曉得了,然則我另有文件給你(ACK=1,ack=u+1,seq=v)。B進入等他文件傳完的狀況(CLOSE-WAIT狀況)。

    A收到B的復興今後,下線不了了,因而繼承守候着B的文件傳完(FIN-WAIT-2狀況)

    幾分鐘后,B的文件傳完了,此時他對A說:我的文件傳完了,我也要下線了(seq=w,FIN=1,ACK=1,ack=u+1),然後B守候A的復興來確認真的能夠下線了(LAST-ACK狀況)

    A收到B的復興后,便對A說:好的,那你下線吧(ACK=1,seq=u+1,ack=w+1)。此時A會守候一段時刻(2MSL,TIME-WAIT狀況),B收到后就直接下線了(CLOSE狀況),然後2MSL時刻到了今後,A也下線(CLOSE狀況)

    • 為何效勞器B在接到A的斷開請求時不馬上贊同斷開?
      當效勞器B收到斷開銜接的請求時,效勞器能夠依然有數據未發送終了,所以效勞器先發送確認信號,等一切數據發送終了后再贊同斷開
    • 為何是四次揮手,而不是像豎立銜接一樣的三次
      因為TCP銜接是全雙工形式,效勞器B收到A的斷開請求時,僅僅表明A沒有東西傳給效勞器B了,但此時效勞器B能夠向A的傳輸還沒完畢,所以效勞器B要先給A一個確認收到A的斷開請求的ACK報文,然後繼承向A把信息傳完,等傳完今後效勞器B再向A發送斷開請求的報文段,等A收到並復興ACK報文後再開釋銜接。
      也就是說關於A來講他要發送請求給B並守候B確認,關於B來講也要發送請求給A並守候A確認,二者都經由這兩個歷程才完全開釋TCP銜接,而非單方面的開釋。
      豎立銜接只須要豎立,沒有數據的影響,而開釋銜接還要斟酌數據是不是傳輸完,所以豎立銜接的時刻B確認收到A的豎立請求與B發送豎立請求這一步能夠合成一步成為TCP豎立銜接的第二次握手,而開釋銜接時卻必需離開。
    • 末了一次握手后A為何要等2MSL
      起首詮釋一下MSLMSL是指最長報文段壽命,RFC793發起為兩分鐘,但實際上可據實際狀況而定,也就是說一個報文段最久可存在的時刻是MSL

      1. 這是為了保證A發送的末了一個ACK報文能夠抵達效勞器B,假如這個ACK報文喪失了,效勞器B沒有收到,B會超時重傳第三次握手的FIN+ACK報文給A,這個時刻處於守候的A就能夠收到這個重傳的FIN+ACK報文,並再次發送ACK報文給效勞器B,而且從新啟動2MSL計時器,終究效果是A和B都一般進入CLOSE狀況。假如A發完ACK報文後就直接開釋了A–>B的銜接,那末A就收不到B重傳的FIN+ACK報文,也不能從新發送ACK`報文,那末B就沒法按一般步驟開釋B–>A的銜接
      2. 防備“已失效的銜接請求報文”出如今下一個新的銜接中,因為一個報文段的壽命是MSL,所以A在發送完末了一個ACK報文段今後,再經由時刻2MSL,本銜接延續的時刻內所發作的一切報文段都將在收集中消逝,如許這些舊的報文段便不會出如今下一個新的銜接中
  • 瀏覽器今後會搜檢HTTP的相應狀況,重要經由過程相應碼來推斷

    1xx: 示意關照信息的,比方請求收到了或正在處置懲罰

    2xx:示意勝利,操縱被勝利吸收並處置懲罰

    3xx:示意重定向,平常完成請求還必需採用進一步的行為

    4xx:示意客戶端的過失

    5xx:示意效勞器的過失

  • 假如相應可緩存,瀏覽器將把相應存入緩存
  • 瀏覽器依據HTTP報頭信息解碼相應,決議怎樣處置懲罰這些相應,並展示相應,以相應為一個HTML為例
  • 瀏覽器最先自上而下,自左而右的加載HTML文檔,最最先會碰到<!DOCTYPE>聲明,然後依據<!DOCTYPE>聲明瀏覽器就曉得該用哪一種範例來剖析這個文檔
  • 再繼承邊加載邊剖析,邊天生DOM樹,加載歷程當中碰到外部CSS文件,瀏覽器便會別的發出一個請求,來獵取CSS文件(歷程和上面說的一樣),獵取CSS後會天生CSS Rule樹。DOM樹和CSS Rule樹天生Render樹,頁面能夠最先邊加載邊襯着了

    • 襯着樹和DOM樹的關聯:那些不可見的DOM元素(如<head>…</head>display=none的元素)不會被插進去襯着樹中;另有像一些節點是相對定位或浮動,這些節點會在文本流以外,因而他們會在襯着樹和DOM樹的差別位置,襯着樹標識出實在的位置,並用一個佔位構造標識出他們本來的位置,而DOM樹上是他們本來的位置
    • 襯着包括”規劃”(layout)和”繪製”(paint)這兩個步驟,所謂”規劃”是指給出每一個DOM節點在瀏覽器窗口中的正確位置,”繪製”是指遍歷Render樹將規劃好的DOM節點繪製在屏幕上。

      《從輸入`URL`到頁面加載完成的過程當中都發生了什麼事情》

  • 瀏覽器繼承加載襯着,假如碰到<script>標籤,瀏覽器會馬上實行(暫不斟酌deferasync屬性),此時會湧現頁面壅塞,不僅要守候文檔中JS文件下載加載終了,還要守候JS剖析實行終了,才夠恢復HTML文檔的加載剖析。

    • 這是瀏覽器為了防備湧現JS修正DOM樹,須要從新構建DOM樹的狀況,DOM樹轉變瀏覽器須要回過頭來從新襯着這部份代碼,所以瀏覽器願望經由過程壅塞其他內容的下載和顯現,來防止湧現更多的不必要的Reflow(稱為迴流或許重排)
    • 假如<script>放在的<head>中,則<body>標籤沒法被加載,那末頁面天然就沒法襯着了,因而這將致使在該JS代碼完全實行完之前,頁面都是一片空缺,用戶體驗異常不好,平常我看到長時刻的空缺頁面,我都異常想直接封閉它。因而會引薦將一切<script>標籤只管放到<body>標籤的底部,以只管削減對全部頁面下載的影響,此時雖然還會存在一個劇本壅塞另一個劇本的題目,然則用戶體驗比上面的好許多,因為用戶看到了大部份內容,而不是空缺
    • defer屬性相當於通知瀏覽器馬上下載,耽誤實行。它使得加載後續文檔元素的歷程將和JS文件的加載并行舉行(異步),然則JS文件的實行要在全部頁面剖析完成今後,DOMContentLoaded事宜觸發之前完成,實行遞次為湧現的先後遞次。(高程中指涌實際中不肯定會根據遞次實行,也不肯定會在DOMContentLoaded事宜觸發之前完成,因而最好只包括一個耽誤劇本,這多是與瀏覽器的完成有關,詳細什麼狀況下會湧現我還不曉得???)
    • async屬性相當於通知瀏覽器馬上下載實行,而且頁面的加載襯着不須要守候該劇本加載和實行,它們二者會異步舉行。標記為async的劇本不會根據它們湧現的先後遞次實行,而是誰先下載完了誰就先實行,它們肯定會在頁面的load事宜觸發之前實行,但能夠會在DOMContentLoaded事宜觸發之前或今後實行。基於前面所說的一點緣由,異步劇本最好不要修正DOM,假如由多個異步劇本,它們之間最好沒有依靠關聯
  • 瀏覽器繼承加載襯着,假如碰到圖片資本,瀏覽器也會別的發出一個請求,來獵取圖片資本,這是異步請求,所以不會比及圖片下載完,而是繼承襯着背面的HTML文檔。
  • 比及效勞器返回圖片文件,假如先前並沒有為這個圖片設定寬高,那末因為圖片佔用了肯定面積,影響了背面段落的排布,瀏覽器會舉行Reflow
  • 然後然後終究和</html>謀面了,此次的頁面加載襯着歷程完成,瀏覽器也是很累了,然後會馬上觸發DOMContentLoaded事宜,該事宜是在構成完全的DOM樹今後就會觸發,而不會剖析圖象、JS文件、CSS文件或其他資本是不是已下載終了
  • 當頁面完全加載后,也就是一切圖象、JS文件、CSS文件等外部資本都加載完成後會觸發load事宜
  • 用戶在頁面上舉行交互時,能夠會致使頁面舉行RepaintReflow

    • Repaint:假如只是轉變了某個元素的背景色彩,筆墨色彩等,不影響元素四周或內部規劃的屬性,將只會引發瀏覽器的Repaint,重繪某一部份
    • Reflow:假如某個部份發作了的變化影響了規劃,那瀏覽器就須要倒回去從新襯着,每次Reflow必然會致使Repaint

尾聲

原本只是想相識相識,效果一入深似海,看似簡樸的操縱背地藏着數不清的小動作,文中也只是觸及了一部份,另有許多相干的歷程沒有觸及到,然則才能有限,照樣慢慢來,臨時就先告一段落,文中若有毛病還請斧正哦~

參考

    原文作者:Cshine
    原文地址: https://segmentfault.com/a/1190000014620172
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞