JS原理知識梳理

從輸入URL到頁面展示,發生了什麼

1. DNS解析,根據域名獲取服務器IP

2. 建立TCP連接

三次握手以建立TCP連接

第一次握手:建立連接時,客戶端發送syn包(syn=j)到服務器,並進入SYN_SENT狀態,等待服務器確認;SYN:同步序列編號(Synchronize Sequence Numbers)。
第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也發送一個SYN包(syn=k),即SYN+ACK包,此時服務器進入SYN_RECV狀態;
第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1),此包發送完畢,客戶端和服務器進入ESTABLISHED(TCP連接成功)狀態,完成三次握手。
補充:

爲什需要三次握手?

​ 《計算機網絡》第四版中講“三次握手”的目的是“爲了防止已失效的連接請求報文段突然又傳送到了服務端,因而產生錯誤”,書中的例子是這樣的,“已失效的連接請求報文段”的產生在這樣一種情況下:client發出的第一個連接請求報文段並沒有丟失,而是在某個網絡結點長時間的滯留了,以致延誤到連接釋放以後的某個時間纔到達server。本來這是一個早已失效的報文段。但server收到此失效的連接請求報文段後,就誤認爲是client再次發出的一個新的連接請求。於是就向client發出確認報文段,同意建立連接。假設不採用“三次握手”,那麼只要server發出確認,新的連接就建立了。由於現在client並沒有發出建立連接的請求,因此不會理睬server的確認,也不會向server發送數據。但server卻以爲新的運輸連接已經建立,並一直等待client發來數據。這樣,server的很多資源就白白浪費掉了。採用“三次握手”的辦法可以防止上述現象發生。例如剛纔那種情況,client不會向server的確認發出確認。server由於收不到確認,就知道client並沒有要求建立連接。”。主要目的防止server端一直等待,浪費資源。

3. 服務器處理請求並返回HTTP報文

4. 瀏覽器顯示 HTML

5. 連接結束

​ 現在的頁面爲了優化請求的耗時,默認都會開啓持久連接(keep-alive),那麼一個TCP連接確切關閉的時機,是這個tab標籤頁關閉的時候。這個關閉的過程就是著名的四次揮手。關閉是一個全雙工的過程,發包的順序的不一定的。一般來說是客戶端主動發起的關閉,過程如下。

四次揮手

對於一個已經建立的連接,TCP使用改進的三次握手來釋放連接(使用一個帶有FIN附加標記的報文段)。TCP關閉連接的步驟如下:
第一步,當主機A的應用程序通知TCP數據已經發送完畢時,TCP向主機B發送一個帶有FIN附加標記的報文段(FIN表示英文finish)。
第二步,主機B收到這個FIN報文段之後,並不立即用FIN報文段回覆主機A,而是先向主機A發送一個確認序號ACK,同時通知自己相應的應用程序:對方要求關閉連接(先發送ACK的目的是爲了防止在這段時間內,對方重傳FIN報文段)。
第三步,主機B的應用程序告訴TCP:我要徹底的關閉連接,TCP向主機A送一個FIN報文段。
第四步,主機A收到這個FIN報文段後,向主機B發送一個ACK表示連接徹底釋放。

補充:

爲什麼連接的時候是三次握手,關閉的時候卻是四次握手?

答:因爲當Server端收到Client端的SYN連接請求報文後,可以直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。但是關閉連接時,當Server端收到FIN報文時,很可能並不會立即關閉SOCKET,所以只能先回復一個ACK報文,告訴Client端,“你發的FIN報文我收到了”。只有等到我Server端所有的報文都發送完了,我才能發送FIN報文,因此不能一起發送。故需要四步握手。

棧和堆

棧:棧會自動分配內存空間,會自動釋放,存放基本類型,佔據固定大小的空間。
基本類型:String,Number,Boolean,Null,Undefined,Symbol

堆:動態分配的內存,大小不定也不會自動釋放,存放引用類型,指那些可能由多個值構成的對象,包含引用類型的變量,實際上保存的是指向該對象的指針。
引用類型:Function,Array,Object

			function Person(name, age, sex) {
				this.name = name;
				this.age = age;
				this.sex = sex;
			}

			function f1(person) {
				//var person = p;
				person.name = "bb";
				person = new Person("aa", 18, 'man');
			}

			var p = new Person("cc", 18, 'man');
			console.log(p.name);//cc
			f1(p);
			console.log(p.name);//bb

js函數傳參方式

ECMAScript中所有函數的參數都是按值傳遞的
看完這個案例,會理解的更加深刻

			var a = 1;
			var b = 2;

			function f1(b, c) {
				a = 100;//100
				b = 100;//100
				c = 100;//100
				console.log(a);//100
				console.log(b);//100
				console.log(c);//100
			}
			// 1  2
			f1(a, b);
			console.log(a);//100
			console.log(b);//2
			console.log(c);// 報錯

js深淺拷貝

淺拷貝:只複製引用,而未複製真正的值。
深拷貝:對目標的完全拷貝,不像淺拷貝那樣只是複製了一層引用,就連值也都複製了。只要進行了深拷貝,它們之後互不影響。

	// 淺拷貝
	const arr = [1,2,3]
	var b = arr
	arr.push(4)
	console.log(b) // 1,2,3,4

	// 深拷貝
	// 利用 JSON 對象中的 parse 和 stringify 實現深拷貝
	// JSON.stringify 是將一個 JavaScript 值轉成一個 JSON 字符串。
	// JSON.parse 是將一個 JSON 字符串轉成一個 JavaScript 值或對象。
	const aa = [1,2,3];
	const bb = JSON.parse(JSON.stringify(aa));
	console.log(aa === bb); // false
	console.log(aa) // 1,2,3
	console.log(bb) // 1,2,3
	aa.push(4)
	console.log(aa) // 1,2,3,4
	console.log(bb) // 1,2,3

結語

參考

https://segmentfault.com/a/1190000006879700.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章