Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
Web 開發(fā)中,有許多情況需要解析 URL,這篇主要學(xué)習(xí)如何使用 URL 對(duì)象實(shí)現(xiàn)這一點(diǎn)。
開始
創(chuàng)建一個(gè)以下內(nèi)容的 HTML 文件,并在瀏覽器中打開。
<html> <head> <title>JavaScript URL parsing</title> </head> <body> <script> // 激動(dòng)人心的代碼即將寫在這里 </script> </body> </html>
如果你想嘗試本文中的任何內(nèi)容,可以將其放在 <script> 標(biāo)記中,保存,重新加載頁面,看看會(huì)發(fā)生什么! 在本教程中,將使用 console.log 來打印所需要的內(nèi)容,你可以打開開發(fā)都工具,來查看內(nèi)容。
什么是 URL
這應(yīng)該是相當(dāng)簡(jiǎn)單的,但讓我們說清楚。 URL 是網(wǎng)頁的地址,可以在瀏覽器中輸入以獲取該網(wǎng)頁的唯一內(nèi)容。 可以在地址欄中看到它:
URL 是統(tǒng)一資源定位符,對(duì)可以從互聯(lián)網(wǎng)上得到的資源的位置和訪問方法的一種簡(jiǎn)潔的表示,是互聯(lián)網(wǎng)上標(biāo)準(zhǔn)資源的地址。互聯(lián)網(wǎng)上的每個(gè)文件都有一個(gè)唯一的 URL,它包含的信息指出文件的位置以及瀏覽器應(yīng)該怎么處理它。
此外,如果你不熟悉基本 URL 路徑的工作方式,可以查看此文學(xué)習(xí)。
URL 不都長(zhǎng)的一樣的
這是一個(gè)快速提醒 - 有時(shí) URL 可能非常奇怪,如下:
:1234/page/?a=b
file:///Users/username/folder/file.png
獲取當(dāng)前URL
獲取當(dāng)前頁面的 URL 非常簡(jiǎn)單 - 我們可以使用 window.location。
試著把這個(gè)添加到我們形如寫的的腳本中:
console.log(window.location);
查看瀏覽器的控制臺(tái):
不是你想要的?這是因?yàn)樗环祷啬阍跒g覽器中看到的實(shí)際 URL 地址——它返回的是一個(gè) URL 對(duì)象。使用這個(gè) URL 對(duì)象,我們可以解析 URL 的不同部分,接下來就會(huì)講到。
創(chuàng)建 URL 對(duì)象
很快就會(huì)看到,可以使用 URL 對(duì)象來了解 URL 的不同部分。如果你想對(duì)任何 URL 執(zhí)行此操作,而不僅僅是當(dāng)前頁面的 URL,該怎么辦? 我們可以通過創(chuàng)建一個(gè)新的 URL 對(duì)象來實(shí)現(xiàn)。 以下是如何創(chuàng)建一個(gè):
var myURL = new URL('https://example.com');
就這么簡(jiǎn)單! 可以打印 myURL 來查看 myURL 的內(nèi)容:
console.log(myURL);
出于本文的目的,將 myURL 設(shè)置為這個(gè)值:
var myURL = new URL('https://example.com:4000/folder/page.html?x=y&a=b#section-2')
將其復(fù)制并粘貼到 <script> 元素中,以便你可以繼續(xù)操作! 這個(gè) URL 的某些部分可能不熟悉,因?yàn)樗鼈儾⒉豢偸潜皇褂?- 但你將在下面了解它們,所以不要擔(dān)心!
URL 對(duì)象的結(jié)構(gòu)
使用 URL 對(duì)象,可以非常輕松地獲取 URL 的不同部分。 以下是你可以從 URL 對(duì)象獲得的所有內(nèi)容。 對(duì)于這些示例,我們將使用上面設(shè)置的 myURL。
href
URL 的 href 基本上是作為字符串(文本)的整個(gè) URL。如果你想把頁面的 URL 作為字符串而不是 URL 對(duì)象,你可以寫 window.location.href。
console.log(myURL.href); // Output: "https://example.com:4000/folder/page.html?x=y&a=b#section-2"
協(xié)議 (protocol)
URL的協(xié)議是一開始的部分。這告訴瀏覽器如何訪問該頁面,例如通過 HTTP 或 HTTPS。 但是還有很多其他協(xié)議,比如 ftp(文件傳輸協(xié)議)和 ws(WebSocket)。通常,網(wǎng)站將使用 HTTP 或 HTTPS。
雖然如果你的計(jì)算機(jī)上打開了文件,你可能正在使用文件協(xié)議! URL對(duì)象的協(xié)議部分包括:,但不包括 //。 讓我們看看 myURL 吧!
console.log(myURL.protocol); // Output: "https:"
主機(jī)名(hostname)
主機(jī)名是站點(diǎn)的域名。 如果你不熟悉域名,則它是在瀏覽器中看到的URL的主要部分 - 例如 google.com 或codetheweb.blog。
console.log(myURL.hostname); // Output: "example.com"
端口(port)
URL 的端口號(hào)位于域名后面,用冒號(hào)分隔(例如 example.com:1234)。 大多數(shù)網(wǎng)址都沒有端口號(hào),這種情況非常罕見。
端口號(hào)是服務(wù)器上用于獲取數(shù)據(jù)的特定“通道” - 因此,如果我擁有 example.com,我可以在多個(gè)不同的端口上發(fā)送不同的數(shù)據(jù)。 但通常域名默認(rèn)為一個(gè)特定端口,因此不需要端口號(hào)。 來看看 myURL 的端口號(hào):
console.log(myURL.port); // Output: "4000"
主機(jī)(host)
主機(jī)只是主機(jī)名和端口放在一起,嘗試獲取 myURL 的主機(jī):
console.log(myURL.host); // Output: "example.com:4000"
來源(origin)
origin 由 URL 的協(xié)議,主機(jī)名和端口組成。 它基本上是整個(gè) URL,直到端口號(hào)結(jié)束,如果沒有端口號(hào),到主機(jī)名結(jié)束。
console.log(myURL.origin); // Output: "https://example.com:4000"
pathname(文件名)
pathname 從域名的最后一個(gè) “/” 開始到 “?” 為止,是文件名部分,如果沒有 “?” ,則是從域名最后的一個(gè) “/” 開始到 “#” 為止 , 是文件部分, 如果沒有 “?” 和 “#” , 那么從域名后的最后一個(gè) “/” 開始到結(jié)束 , 都是文件名部分。
console.log(myURL.pathname); // Output: "/folder/page.html"
錨點(diǎn)(hash)
從 “#” 開始到最后,都是錨部分。可以將哈希值添加到 URL 以直接滾動(dòng)到具有 ID 為該值的哈希值 的元素。 例如,如果你有一個(gè) id 為 hello 的元素,則可以在 URL 中添加 #hello 就可以直接滾動(dòng)到這個(gè)元素的位置上。通過以下方式可以在 URL 獲取 “#” 后面的值:
console.log(myURL.hash); // Output: "#section-2"
查詢參數(shù) (search)
你還可以向 URL 添加查詢參數(shù)。它們是鍵值對(duì),意味著將特定的“變量”設(shè)置為特定值。 查詢參數(shù)的形式為 key=value。 以下是一些 URL 查詢參數(shù)的示例:
?key1=value1&key2=value2&key3=value3
請(qǐng)注意,如果 URL 也有 錨點(diǎn)(hash),則查詢參數(shù)位于 錨點(diǎn)(hash)(也就是 ‘#’)之前,如我們的示例 URL 中所示:
console.log(myURL.search); // Output: "?x=y&a=b"
但是,如果我們想要拆分它們并獲取它們的值,那就有點(diǎn)復(fù)雜了。
使用 URLSearchParams 解析查詢參數(shù)
要解析查詢參數(shù),我們需要?jiǎng)?chuàng)建一個(gè) URLSearchParams 對(duì)象,如下所示:
var searchParams = new URLSearchParams(myURL.search);
然后可以通過調(diào)用 searchParams.get('key')來獲取特定鍵的值。 使用我們的示例網(wǎng)址 - 這是原始搜索參數(shù):
?x=y&a=b
因此,如果我們調(diào)用 searchParams.get('x'),那么它應(yīng)該返回 y,而 searchParams.get('a')應(yīng)該返回 b,我們來試試吧!
console.log(searchParams.get('x')); // Output: "y" console.log(searchParams.get('a')); // Output: "b"
擴(kuò)展
獲取 URL 的中參數(shù)
方法一:正則法
function getQueryString(name) { var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i'); var r = window.location.search.substr(1).match(reg); if (r != null) { return unescape(r[2]); } return null; } // 這樣調(diào)用: alert(GetQueryString("參數(shù)名1")); alert(GetQueryString("參數(shù)名2")); alert(GetQueryString("參數(shù)名3"));
方法二:split拆分法
function GetRequest() { var url = location.search; //獲取url中"?"符后的字串 var theRequest = new Object(); if (url.indexOf("?") != -1) { var str = url.substr(1); strstrs = str.split("&"); for(var i = 0; i < strs.length; i ++) { theRequest[strs[i].split("=")[0]] = unescape(strs[i].split("=")[1]); } } return theRequest; } var Request = new Object(); Request = GetRequest(); // var 參數(shù)1,參數(shù)2,參數(shù)3,參數(shù)N; // 參數(shù)1 = Request['參數(shù)1']; // 參數(shù)2 = Request['參數(shù)2']; // 參數(shù)3 = Request['參數(shù)3']; // 參數(shù)N = Request['參數(shù)N'];
修改 URL 的中某個(gè)參數(shù)值
阿里架構(gòu)師精選Nginx+Redis+Sping+SpringBoot源碼級(jí)PDF文檔分享
微服務(wù)+Docker完美教程,被阿里架構(gòu)師匯集到這2份文檔里面了!
對(duì)于面試常問的從瀏覽器輸入 URL 到頁面展示過程發(fā)生了什么?,我想大家都或多或少能說出一二。但是,其實(shí)這個(gè)問題很有深度,而你是否回答的有深度,在很大程度上會(huì)影響到面試官對(duì)你的印象。
并且,網(wǎng)上各種資料都是淺嘗輒止地講解這個(gè)過程,經(jīng)常會(huì)出現(xiàn)今天看到這個(gè)版本,明天看到另一個(gè)版本地情況。所以,這次我們就來深入淺出一下這整個(gè)過程~
首先,在開始講解整個(gè)過程前,我們需要認(rèn)識(shí)一下 Chrome 多進(jìn)程架構(gòu)。因?yàn)椋瑥臑g覽器輸入 URL 到頁面渲染的整個(gè)過程都是由 Chrome 架構(gòu)中的各個(gè)進(jìn)程之間的配合完成。
Chrome 的多進(jìn)程架構(gòu):
發(fā)生這個(gè)過程的前提,用戶在地址欄中輸入了 URL,而地址欄會(huì)根據(jù)用戶輸入,做出如下判斷:
在網(wǎng)絡(luò)進(jìn)程接收到 URL 后,并不是馬上對(duì)指定 URL 進(jìn)行請(qǐng)求。首先,我們需要進(jìn)行 DNS 解析域名得到對(duì)應(yīng)的 IP,然后通過 ARP 解析 IP 得到對(duì)應(yīng)的 MAC(Media Access Control Address)地址。
域名是我們?nèi)〈洃洀?fù)雜的 IP 的一種解決方案,而 IP 地址才是目標(biāo)在網(wǎng)絡(luò)中所被分配的節(jié)點(diǎn)。MAC 地址是對(duì)應(yīng)目標(biāo)網(wǎng)卡所在的固定地址。
1. DNS 解析
而 DNS 解析域名的過程分為以下幾個(gè)步驟:
2. 通信過程
首先,建立 TCP 連接,即三次握手過程:
然后,利用 TCP 通道進(jìn)行數(shù)據(jù)傳輸:
最后,斷開 TCP 連接,即四次握手過程:
而這整個(gè)過程的客戶端則是網(wǎng)絡(luò)進(jìn)程。并且,在數(shù)據(jù)傳輸?shù)倪^程還可能會(huì)發(fā)生的重定向的情況,即當(dāng)網(wǎng)絡(luò)進(jìn)程接收到狀態(tài)碼為 3xx 的響應(yīng)報(bào)文,則會(huì)根據(jù)響應(yīng)報(bào)文首部字段中的 Location 字段的值進(jìn)行重新向,即會(huì)重新發(fā)起請(qǐng)求
3. 數(shù)據(jù)處理
當(dāng)網(wǎng)絡(luò)進(jìn)程接收到的響應(yīng)報(bào)文狀態(tài)碼,進(jìn)行相應(yīng)的操作。例如狀態(tài)碼為 200 OK 時(shí),會(huì)解析響應(yīng)報(bào)文中的 Content-Type 首部字段,例如我們這個(gè)過程 Content-Type 會(huì)出現(xiàn) application/javascript、text/css、text/html,即對(duì)應(yīng) Javascript 文件、CSS 文件、HTML 文件。
詳細(xì)的 MIME 類型講解可以看 MDN
當(dāng)前需要渲染 HTML 時(shí),則需要?jiǎng)?chuàng)建渲染進(jìn)程,用于后期渲染 HTML。而對(duì)于渲染進(jìn)程,如果是同一站點(diǎn)是可以共享一個(gè)渲染進(jìn)程,例如 a.abc.com 和 c.abc.com 可以共享一個(gè)渲染渲染進(jìn)程。否則,需要重新創(chuàng)建渲染進(jìn)程
需要注意的是,同站指的是頂級(jí)域名和二級(jí)域名相等
在創(chuàng)建完渲染進(jìn)程后,網(wǎng)絡(luò)進(jìn)程會(huì)將接收到的 HTML、JavaScript 等數(shù)據(jù)傳遞給渲染進(jìn)程。而在渲染進(jìn)程接收完數(shù)據(jù)后,此時(shí)用戶界面上會(huì)發(fā)生這幾件事:
大家都知道頁面渲染的過程也是面試中單獨(dú)會(huì)考的點(diǎn),并且時(shí)常會(huì)由這個(gè)點(diǎn)延申出另一個(gè)問題,即如何避免回流和重繪。
渲染過程,是整個(gè)從理器輸入 URL 到頁面渲染過程的最后一步。而頁面渲染的過程可以分為 9 個(gè)步驟:
由于網(wǎng)絡(luò)進(jìn)程傳輸給渲染進(jìn)程的是 HTML 字符串,所以,渲染進(jìn)程需要將 HTML 字符串轉(zhuǎn)化成 DOM 樹。例如:
需要注意的是這個(gè) DOM 樹不同于 Chrome-devtool 中 Element 選項(xiàng)卡的 DOM 樹,它是存在內(nèi)存中的,用于提供 JavaScript 對(duì) DOM 的操作。
構(gòu)建 CSSOM 的過程,即通過解析 CSS 文件、style 標(biāo)簽、行內(nèi) style 等,生成 CSSOM。而這個(gè)過程會(huì)做這幾件事:
CSS Object Model 是一組允許用 JavaScript 操縱 CSS 的 API。詳細(xì) API 講解可以看 MDN
通常情況下,在構(gòu)建 DOM 樹或 CSSOM 的同時(shí),如果也要加載 JavaScript,則會(huì)造成前者的構(gòu)建的暫停。當(dāng)然,我們可以通過 defer 或 sync 來實(shí)現(xiàn)異步加載 JavaScript。雖然 defer 和 sync 都可以實(shí)現(xiàn)異步加載 JavaScript,但是前者是在加載后,等待 CSSOM 和 DOM 樹構(gòu)建完后才執(zhí)行 JavaScript,而后者是在異步加載完馬上執(zhí)行,即使用 sync 的方式仍然會(huì)造成阻塞。
而 JavaScript 執(zhí)行的過程,即編譯和運(yùn)行 JavaScript 的過程。由于 JavaScript 是解釋型的語言。所以這個(gè)過程會(huì)是這樣的:
在有了 DOM 樹和 CSSOM 之后,需要將兩者結(jié)合生成渲染樹 Render Tree,并且這個(gè)過程會(huì)去除掉那些 display: node 的節(jié)點(diǎn)。此時(shí),渲染樹就具備元素和元素的樣式信息。
根據(jù) Render Tree 渲染樹,對(duì)樹中每個(gè)節(jié)點(diǎn)進(jìn)行計(jì)算,確定每個(gè)節(jié)點(diǎn)在頁面中的寬度、高度和位置。
需要注意的是,第一次確定節(jié)點(diǎn)的大小和位置的過程稱為布局,而第二次才被稱為回流
由于層疊上下文的存在,渲染引擎會(huì)為具備層疊上下文的元素創(chuàng)建對(duì)應(yīng)的圖層,而諸多圖層的疊加就形成了我們看到的一些頁面效果。例如,一些 3D 的效果、動(dòng)畫就是基于圖層而形成的。
值得一提的是,對(duì)于內(nèi)容溢出存在滾輪的情況也會(huì)進(jìn)行分層
對(duì)于存在圖層的頁面部分,需要進(jìn)行有序的繪制,而對(duì)于這個(gè)過程,渲染引擎會(huì)將一個(gè)個(gè)圖層的繪制拆分成繪制指令,并按照?qǐng)D層繪制順序形成一個(gè)繪制列表。
有了繪制列表后,渲染引擎中的合成線程會(huì)根據(jù)當(dāng)前視口的大小將圖層進(jìn)行分塊處理,然后合成線程會(huì)對(duì)視口附近的圖塊生成位圖,即光柵化。而渲染進(jìn)程也維護(hù)了一個(gè)柵格化的線程池,專門用于將圖塊轉(zhuǎn)為位圖。
柵格化的過程通常會(huì)使用 GPU 加速,例如使用 wil-change、opacity,就會(huì)通過 GPU 加速顯示
當(dāng)所有的圖塊都經(jīng)過柵格化處理后,渲染引擎中的合成線程會(huì)生成繪制圖塊的指令,提交給瀏覽器進(jìn)程。然后瀏覽器進(jìn)程將頁面繪制到內(nèi)存中。最后將內(nèi)存繪制結(jié)果顯示在用戶界面上。
而這個(gè)整個(gè)從生成繪制列表、光柵化、顯示的過程,就是我們常說的重繪的過程
整個(gè)瀏覽器輸入 URL 到頁面渲染的過程涉及到的知識(shí)點(diǎn)非常廣,如 Chrome 多進(jìn)程的架構(gòu)、HTTP 通信過程、瀏覽器解析 JavaScript 過程、瀏覽器繪制頁面過程以及一些計(jì)算機(jī)的基礎(chǔ)知識(shí)等等,并且,這整個(gè)過程的分析其實(shí)和 Chrome-devtools 密切相關(guān),所以很好的使用 Chrome-devtools 是非常重要的,后續(xù)應(yīng)該會(huì)出一篇關(guān)于使用 Chrome-devtools 的指南。當(dāng)然,本篇文章仍然存在諸多不足,歡迎提 issue ~
作者:五柳
鏈接:https://juejin.im/post/5e871ee56fb9a03c832b0013
我們向?yàn)g覽器的地址欄輸入U(xiǎn)RL的時(shí)候,網(wǎng)絡(luò)會(huì)進(jìn)行一系列的操作,最終獲取到我們所需要的文件,如何交給瀏覽器進(jìn)行渲染
我們所關(guān)注的問題也就是:
瀏覽器先會(huì)判斷輸入的字符是不是一個(gè)合法的URL結(jié)構(gòu),如果不是,瀏覽器會(huì)使用搜索引擎對(duì)這個(gè)字符串進(jìn)行搜索
URL結(jié)構(gòu)組成
https://www.example.com:80/path/to/myfile.html?key1=value1&key2=value2#anchor
DNS(Domain Names System),域名系統(tǒng),是互聯(lián)網(wǎng)一項(xiàng)服務(wù),是進(jìn)行域名和與之相對(duì)應(yīng)的 IP 地址進(jìn)行轉(zhuǎn)換的服務(wù)器
判斷是正確的URL格式之后,DNS會(huì)在我們的緩存中查詢是否有當(dāng)前域名的IP地址
基本步驟:
在經(jīng)歷上述緩存查找還沒有找到的話,就進(jìn)行下一步查詢操作
瀏覽器會(huì)去根域名服務(wù)器中查找,如果還沒有就去頂級(jí)域名服務(wù)器中查找,最后是權(quán)威域名服務(wù)器。
找到IP地址后,將它記錄在緩存中,供下次使用。
簡(jiǎn)單的理解就是:
客戶端:hello,你好,你是server嗎?
服務(wù)端:hello,你好,我是server,你是client嗎
客戶端:yes,我是client
開始數(shù)據(jù)傳輸.....
——————————————————————————————————————————
客戶端(男人):我喜歡你,咱倆處對(duì)象吧
服務(wù)端(女人):我也喜歡你,我答應(yīng)你
客戶端(男人):太棒了,我們現(xiàn)在去看電影吧
開始數(shù)據(jù)傳輸.....
然后雙方就正確建立連接,開始傳輸數(shù)據(jù)
然后雙方就正確建立連接,開始傳輸數(shù)據(jù)
HTTPS 建立連接的過程,先進(jìn)行 TCP 三次握手,再進(jìn)行 TLS 四次握手(僅對(duì)https)
因?yàn)?HTTPS 都是基于 TCP 傳輸協(xié)議實(shí)現(xiàn)的,得先建立完可靠的 TCP 連接才能做 TLS 握手的事情。
客戶端收到服務(wù)器回應(yīng)以后,首先驗(yàn)證服務(wù)器證書,驗(yàn)證手段就是執(zhí)行如下三種檢查:
如果,上述過程中有任何一個(gè)環(huán)節(jié)發(fā)現(xiàn)問題,那么瀏覽器就會(huì)向訪問者顯示一個(gè)警告,由其選擇是否還要繼續(xù)通信。如果證書受信任,或者是用戶接受了不受信的證書,瀏覽器會(huì)生成一串新的隨機(jī)數(shù)(Premaster secret )。
此時(shí),瀏覽器會(huì)根據(jù)前三次握手中的三個(gè)隨機(jī)數(shù):
通過一定的算法來生成 “會(huì)話密鑰” (Session Key),這個(gè)會(huì)話密鑰就是接下來雙方進(jìn)行對(duì)稱加密解密使用的密鑰!
服務(wù)端收到客戶端的回復(fù),利用已知的加密解密方式進(jìn)行解密,服務(wù)器收到客戶端的第三個(gè)隨機(jī)數(shù)( Premaster secret) 之后,使用同樣的算法計(jì)算出 “會(huì)話密鑰” (Session Key)。
至此,整個(gè)握手階段全部結(jié)束。接下來,客戶端與服務(wù)器進(jìn)入加密通信,就完全是使用普通的 HTTP 協(xié)議,只不過用 “會(huì)話密鑰” 加密內(nèi)容。(非對(duì)稱加密解密將不再使用,接下來完全由對(duì)稱加密接手了,因?yàn)槊荑€已經(jīng)安全的傳送給了通信的雙方)
連接建立成功之后,瀏覽器向服務(wù)器發(fā)送HTTP請(qǐng)求報(bào)文,來獲取自己想要的數(shù)據(jù)
請(qǐng)求報(bào)文由請(qǐng)求行、請(qǐng)求頭、空行、請(qǐng)求體四部分組成
服務(wù)器對(duì)http請(qǐng)求報(bào)文進(jìn)行解析,并給客戶端發(fā)送HTTP響應(yīng)報(bào)文對(duì)其進(jìn)行響應(yīng)
HTTP響應(yīng)報(bào)文也是由狀態(tài)行、響應(yīng)頭、空行、響應(yīng)體四部分組成
這個(gè)時(shí)候?yàn)g覽器拿到我們服務(wù)器返回的HTML文件,可以開始解析渲染頁面
當(dāng)我們經(jīng)歷了上述的一系列步驟之后,我們的瀏覽器就拿到了我的HTML文件那么它又是如何解析整個(gè)頁面并且最終呈現(xiàn)出我們的網(wǎng)頁呢?
簡(jiǎn)圖:從這張圖上我們可以得出一個(gè)重要的結(jié)論:下載CSS文件并不會(huì)阻塞HTML的解析
詳圖:
默認(rèn)情況下服務(wù)器會(huì)給瀏覽器返回index.html文件,所以解析HTML是所有步驟的開始:解析HTML,會(huì) 構(gòu)建DOM Tree
當(dāng)遇到我們的script文件的時(shí)候,我們是不能進(jìn)行去構(gòu)建DOM Tree的。它會(huì)停止繼續(xù)構(gòu)建,首先下載JavaScript代碼,并且執(zhí)行JavaScript的腳本,只有等到JavaScript腳本執(zhí)行結(jié)束后,才會(huì)繼續(xù)解析HTML,構(gòu)建DOM樹。
具體的相關(guān)細(xì)節(jié)看下面的script與頁面解析
當(dāng)有了 DOM Tree 和 CSSOM Tree 后,就可以兩個(gè)結(jié)合來 構(gòu)建 Render Tree
<script src="./foo.js" defer></script>
<script>
window.addEventListener("DOMContentLoaded",()=>{
console.log("DOMContentLoaded");
})
</script>
在渲染完成后,瀏覽器可能會(huì)繼續(xù)加載頁面中的其他資源,如異步加載的內(nèi)容或者通過JavaScript生成的動(dòng)態(tài)內(nèi)容。
而在此過程中,如果沒有其他資源需要加載,瀏覽器將與服務(wù)器之間的TCP連接斷開。
復(fù)制代碼主動(dòng)方:我已經(jīng)關(guān)閉了向你那邊的主動(dòng)通道了,這是我最后一次給你發(fā)消息了,之后只能被動(dòng)接收你的信息了
被動(dòng)方:收到你通道關(guān)閉的信息
被動(dòng)方:那我也告訴你,我這邊向你的主動(dòng)通道也關(guān)閉了
主動(dòng)方:最后收到你關(guān)閉的信息,OK結(jié)束
斷開連接,結(jié)束通訊
————————————————————————————————————————————————————————————————————————————
提出分手的可能是男生(客戶端),也可能是女生(服務(wù)端)
主動(dòng)方:分手吧,我不喜歡你了!
被動(dòng)方:行,你等我忙完手上的工作我在收拾你!
被動(dòng)方:我忙完了,分手就分手!
主動(dòng)方:好,好聚好散,拜拜!
斷開連接,結(jié)束通訊
由于TCP連接是全雙工的,因此,每個(gè)方向都必須要單獨(dú)進(jìn)行關(guān)閉,這一原則是當(dāng)一方完成數(shù)據(jù)發(fā)送任務(wù)后,發(fā)送一個(gè)FIN來終止這一方向的連接,收到一個(gè)FIN只是意味著這一方向上沒有數(shù)據(jù)流動(dòng)了,即不會(huì)再收到數(shù)據(jù)了,但是在這個(gè)TCP連接上仍然能夠發(fā)送數(shù)據(jù),直到這一方向也發(fā)送了FIN。首先進(jìn)行關(guān)閉的一方將執(zhí)行主動(dòng)關(guān)閉,而另一方則執(zhí)行被動(dòng)關(guān)閉。
任何一方都可以在數(shù)據(jù)傳送結(jié)束后發(fā)出連接釋放的通知,所有主動(dòng)發(fā)起關(guān)閉請(qǐng)求可以是客戶端,也可以是服務(wù)端
這里我們假設(shè)是由客戶端先主動(dòng)發(fā)起關(guān)閉請(qǐng)求
之后斷開連接,結(jié)束通訊
作者:前端實(shí)習(xí)生鯨落
鏈接:https://juejin.cn/post/7279093851000242234
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。