玩轉javaScript---知識點彙總(3)

1.瀏覽器從輸入URL到渲染完頁面的整個過程

  1. 瀏覽器先查看瀏覽器緩存-系統緩存-路由器緩存,若緩存中有,請略過中間步驟,直接跳到第9步~若沒有,則按照下面的步驟進行操做。
  2. 瀏覽器從url中解析出服務器的主機名,並將主機名轉換成服務器的IP地址(DNS查詢)
  3. 瀏覽器創建一條與服務器的tcp鏈接(創建過程:三次握手)。瀏覽器利用IP直接與網站主機通訊。瀏覽器發出TCP(SYN標誌位爲1)鏈接請求,主機返回TCP(SYN,ACK標誌位均爲1)應答報文,瀏覽器收到應答報文發現ACK標誌位爲1,表示鏈接請求確認。瀏覽器返回TCP()確認報文,主機收到確認報文,三次握手,TCP連接創建完成。
  4. 瀏覽器經過tcp鏈接向服務器發送http請求,請求數據包。
  5. 服務器處理HTTP請求,返回響應。
  6. 瀏覽器檢查HTTP響應是否爲一個重定向(3XX結果狀態碼)、一個驗證請求(401)、錯誤(4XX、5XX)等等,這些都須要根據具體狀況分類處理。
  7. 瀏覽器接收HTTP響應而且可能關掉TCP鏈接,或者是從新創建鏈接使用新情求,得到新響應。
  8. 瀏覽器渲染頁面:1. 解析HTML 2. 構建DOM樹 3. DOM樹與CSS樣式進行附着構造呈現樹 4. 佈局 5. 繪製 上述這個過程是逐步完成的,爲了更好的用戶體驗,渲染引擎將會盡量早的將內容呈現到屏幕上,並不會等到全部的html都解析完成以後再去構建和佈局render樹。它是解析完一部份內容就顯示一部份內容,同時,可能還在經過網絡下載其他內容。

2.javascript的併發模型與事件循環

棧:函數調用造成了一個棧幀。javascript

function foo(b) {
  var a = 10;
  return a + b + 11;
}

function bar(x) {
  var y = 3;
  return foo(x * y);
}

console.log(bar(7));
複製代碼

當調用bar時,建立了第一個幀 ,幀中包含了bar的參數和局部變量。當bar調用foo時,第二個幀就被建立,並被壓到第一個幀之上,幀中包含了foo的參數和局部變量。當foo返回時,最上層的幀就被彈出棧(剩下bar函數的調用幀 )。當bar返回的時候,棧就空了。
html

堆:對象被分配在一個堆中,即用以表示一個大部分非結構化的內存區域。java

隊列:一個 JavaScript 運行時包含了一個待處理的消息隊列。每個消息都有一個爲了處理這個消息相關聯的函數。web

在事件循環時,runtime (運行時)老是從最早進入隊列的一個消息開始處理隊列中的消息。正因如此,這個消息就會被移出隊列,並將其做爲輸入參數調用與之關聯的函數。爲了使用這個函數,調用一個函數老是會爲其創造一個新的棧幀( stack frame),一如既往。 函數的處理會一直進行直到執行棧再次爲空;而後事件循環(event loop)將會處理隊列中的下一個消息(若是還有的話)。
跨域

事件循環:之因此稱爲事件循環,是由於它常常被用於相似以下的方式來實現:
數組

while (queue.waitForMessage()) {
  queue.processNextMessage();
}複製代碼

"執行至完成"
瀏覽器

每個消息完整的執行後,其它消息纔會被執行。當你分析你的程序時,這點提供了一些優秀的特性,包括每當一個函數運行時,它就不能被搶佔,而且在其餘代碼運行以前徹底運行(且能夠修改此函數操做的數據)。這與C語言不一樣,例如,若是函數在線程中運行,則能夠在任何位置終止而後在另外一個線程中運行其餘代碼。緩存

這個模型的一個缺點在於當一個消息須要太長時間才能完成,Web應用沒法處理用戶的交互,例如點擊或滾動。瀏覽器用「程序須要過長時間運行」的對話框來緩解這個問題。一個很好的作法是使消息處理縮短,若是可能,將一個消息裁剪成幾個消息。bash

添加消息
服務器

在瀏覽器裏,當一個事件出現且有一個事件監聽器被綁定時,消息會被隨時添加。若是沒有事件監聽器,事件會丟失。因此點擊一個附帶點擊事件處理函數的元素會添加一個消息。其它事件亦然。

調用 setTimeout 函數會在一個時間段過去後在隊列中添加一個消息。這個時間段做爲函數的第二個參數被傳入。若是隊列中沒有其它消息,消息會被立刻處理。可是,若是有其它消息,setTimeout消息必須等待其它消息處理完。所以第二個參數僅僅表示最少的時間 而非確切的時間。

零延遲

零延遲並非意味着回調會當即執行。在零延遲調用 setTimeout 時,其並非過了給定的時間間隔後就立刻執行回調函數。其等待的時間基於隊列里正在等待的消息數量。在下面的例子中,"this is just a message" 將會在回調 (callback) 得到處理以前輸出到控制檯,這是由於延遲是要求運行時 (runtime) 處理請求所需的最小時間,但不是有所保證的時間。

(function() {

  console.log('this is the start');

  setTimeout(function cb() {
    console.log('this is a msg from call back');
  });

  console.log('this is just a message');

  setTimeout(function cb1() {
    console.log('this is a msg from call back1');
  }, 0);

  console.log('this is the end');

})();

// "this is the start"
// "this is just a message"
// "this is the end"
// note that function return, which is undefined, happens here 
// "this is a msg from call back"
// "this is a msg from call back1"
複製代碼

多個運行時互相通訊

一個 web worker 或者一個跨域的iframe都有本身的棧,堆和消息隊列。兩個不一樣的運行時只能經過 postMessage方法進行通訊。若是後者偵聽到message事件,則此方法會向其餘運行時添加消息。

永不阻塞

事件循環模型的一個很是有趣的特性是 JavaScript,與許多其餘語言不一樣,它永不阻塞。 處理 I/O 一般經過事件和回調來執行,因此當一個應用正等待IndexedDB查詢返回或者一個 XHR 請求返回時,它仍然能夠處理其它事情,如用戶輸入。 例外是存在的,如 alert或者同步 XHR,但應該儘可能避免使用它們。

上面的內容摘自MDN,看起來是否是有點官方,其實所謂的事件循環就是javascript的主線程重複從消息隊列中取消息、執行的過程。

3.WebSocket的底層原理

首先HTTP有1.1和1.0之說,也就是所謂的keep-alive,把多個HTTP請求合併爲一個,可是Websocket實際上是一個新協議,跟HTTP協議基本沒有關係,只是爲了兼容現有瀏覽器的握手規範而已,也就是說它是HTTP協議上的一種補充能夠經過這樣一張圖理解

Websocket實現了瀏覽器與服務器全雙工通訊,能更好的節省服務器資源和帶寬並達到實時通信的目的。它與HTTP同樣經過已創建的TCP鏈接來傳輸數據。websocket是一個持久化鏈接的協議,一個典型的websocket鏈接:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
複製代碼

熟悉http協議的可以看出來,它比http協議多了幾個東西,以下就是重點,用於告知服務器咱們客戶端使用的是websocket協議,不是那老套的http協議。

Upgrade: websocket
Connection: Upgrade
複製代碼

Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
複製代碼

首先,Sec-WebSocket-Key 是一個Base64 encode的值,這個是瀏覽器隨機生成的,用於驗證服務器,要求服務端必須返回一個對應加密的Sec-WebSocket-Accept應答,不然客戶端會拋出Error during WebSocket handshake錯誤,並關閉鏈接。Sec_WebSocket-Protocol 是一個用戶定義的字符串,用來區分同URL下,不一樣的服務所須要的協議。Sec-WebSocket-Version 是告訴服務器所使用的Websocket Draft(協議版本),而後服務器會返回下列東西,表示已經接受到請求, 成功創建Websocket,後續服務器與瀏覽器之間的通信不須要向http協議那樣重複發送httpHeader。

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
複製代碼

4.typeof運算符對各個類型的返回結果

1.undefined:undefined

2.null:object

3.string:string

4.number:number

5.boolean:boolean

6.function:function

7.object:object

8.array:object(Array:function)

9.NaN:number

5.判斷是否爲數組

1.instanceof :

var ary = [2,3];
console.log(ary instanceof Array)//true;
複製代碼

2.原型鏈方法

var ary = [2,4];
console.log(ary.__proto__.constructor==Array);//true
console.log(ary.constructor==Array)//true 這兩段代碼是同樣的
複製代碼

上述兩種方法都是有侷限性的:

instanceof 和constructor 判斷的變量,必須在當前頁面聲明的,好比,一個頁面(父頁面)有一個框架,框架中引用了一個頁面(子頁面),在子頁面中聲明瞭一個arr,並將其賦值給父頁面的一個變量,這時判斷該變量,Array == arr.constructor;會返回false;緣由就是Array是引用型數據,1.在傳遞過程當中,僅僅是引用地址的傳遞。 2.每一個頁面的Array原生對象所引用的地址是不同的,在子頁面聲明的array,所對應的構造函數,是子頁面的Array對象;父頁面來進行判斷,使用的Array並不等於子頁面的Array,從而形成原型鏈的斷裂。

3. Object.prototype.toString.call()

採用Object.prototype.toString.call()算是最穩定也是通用的一個方法,Object.prototype.toString()返回一個表示該對象的字符串,每一個對象都有一個toString()方法,當該對象被表示爲一個文本值時,或者一個對象以預期的字符串方式引用時自動調用。默認狀況下,toString()方法被每一個Object對象繼承。若是此方法在自定義對象中未被覆蓋,toString() 返回 "[object type]",其中type是對象的類型。

var arr = [2,3];
function isArray(o){
return Object.prototype.toString.call(o)=='[object Array]';
}
console.log(isArray(arr));
複製代碼

6.實現一個柯里化函數

場景:記錄一個員工一個月的總加班時間,咱們首先想到的可能會是這樣實現:

var sumTime = 0;
function  overTime(time){
    return sumTime += time;
}

overTime(3.0);
overTime(7);
overTime(4.5);
......
console.log(overTime());複製代碼

逐次累加,這樣看起來一點毛病都沒有,可是當數據量很大時,就會影響性能了,那麼這時柯里化就能夠解決咱們的問題了。咱們能夠不用每次都疊加,只須要將每次加班的時間保存起來,到最後再疊加就ok了。

var overTime = (function(){  var args = [];  return function () {     if(arguments.length === 0){      var time = 0;      for(var i = 0;len = args.length,i<len;i++){        time += args[i];      }      return time;    }else{      [].push.apply(args, arguments);    }   }})()
overTime(3.0);overTime(4.5);overTime(7.0);console.log(overTime());//14.5複製代碼

看到這裏你應該有點理解什麼叫函數柯里化了,柯里化(英語:Currying),又譯爲卡瑞化或加里化,是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,而且返回接受餘下的參數並且返回結果的新函數的技術。

相關文章
相關標籤/搜索