客戶端的js js指令碼的引入 js的解析過程

weixin_34253539發表於2018-08-02

web瀏覽器中的JavaScript
web瀏覽器中的js通常稱為客戶端的JavaScript

客戶端 JavaScript

window物件是所有客戶端JavaScript特性和api的主要接入點。
即,表示web瀏覽器一個視窗或窗體。使用識別符號window來完成引用。

屬性

window物件定義了一些屬性,用來指定當前視窗的一些資訊。通過該屬性的引用,可以獲取當前視窗的資訊

// web API 介面 獲取當前頁面的資訊,返回一個頁面資訊的物件
window.location
// 所有的必須小寫,為只讀屬性。
// 設定localtion屬性,完成跳轉到一個新的頁面,即使是原來的連結也會完成跳轉
window.location = "https://www.google.com.hk";

注意,該屬性為只讀屬性,不可進行修改,能進行賦值操作,並不意味著能進行修改。進行賦值以後會完成頁面的跳轉,而讓其達到被修改的目的。

方法

window還定義了一些方法,alert()彈出對話方塊,以及setTimeout()註冊一個函式,在給定的一段時間以後觸發回撥

> setTimeout(() => {alert("hello word!");}, 2000);
2

返回值為一個定時器的編號,該定時器和window.setInterval(重複呼叫一個函式,或執行一段程式碼)共用一個編碼池。
該程式碼,並沒有顯式的使用window屬性。但是依然隱式的使用了window屬性。因為window為全域性物件,即window物件處於作用域鏈的頂部,其屬性以及方法為全域性變數和全域性函式。在沒有直接說明的時候,自動從作用域鏈往上尋找,直到window頂部。window物件有一個引用自身的屬性,即window,如果要引用其視窗本身,可以用window這個屬性。
即上方程式碼和下方程式碼等價

> window.setTimeout(() => {alert("hello word!");}, 2000);
2

一個屬性document

該屬性引用Document物件,為window物件的一個屬性。該屬性有一些方法。該方法同時也為document屬性的一些方法(因為是引用關係)
例如

// 尋找 id = "timestamp" 的元素
> var timestamp = document.getElementById("timestamp");
undefined
> timestamp;
<div id="timestamp">
// 獲取指令碼的內容
> timestamp.firstChild
#text "2222222"
// 插入當前時間
> timestamp.appendChild(document.createTextNode(new Date().toString()))

html嵌入js

html嵌入js有四種方法

  1. 內聯,放置在
<script>

</script>

標籤對之間

  1. 放置在
<script>

標籤的src屬性指定的外部檔案中

  1. 放置在html事件處理程式中,該事件處理程式由onclick或onmouseover這樣的html屬性值指定
  2. 放在一個url裡,這個url使用javascript:協議

後兩個用的很少
因為需要html和js分離,依據mvc進行分離,使得html變的結構化,易於閱讀

script元素

下面是一個數字時鐘使用onload事件處理程式

Element.innerHTML 屬性設定或獲取HTML語法表示的元素的後代。
<!DOCTYPE html>
<html>
<head>
    <title>數字時鐘</title>
    <script>
        // 定義一個函式顯示當前時間
        function displayTime() {
            var elt = document.getElementById('clock');    // 通過id尋找到元素
            var now = new Date();    // 得到當前時間
            elt.innerHTML = now.toLocaleTimeString();    // 讓elt來顯示
            setTimeout(displayTime, 1000);    // 讓其1秒後執行
        }
        window.onload = displayTime; // 當頁面或影像載入完成以後顯示時間
    </script>
    <style>
    #clock {
        font:bold 24pt sans;    /*設定字型*/
        background:#ddf;    /*設定藍灰色的背景*/
        padding:10px;    /*周圍有一圈空白*/
        border:solid black 2px;    /*定義純黑色邊框*/
        border-radius:10px;    /*定義圓角*/
    }
    </style>
</head>
<body>
    <h1>Digital Clock</h1>
    <div id="clock"></div>
</body>
</html>

外部檔案中指令碼

使用

<script src="./script/util.js"></script>

的src屬性進行引用
可以在標籤內部加上版權以及配置

<script src="core.js">
    config = {..}
</script>

定義了一個配置項,由core.js讀取。將頁面的引數傳入庫的一種手法。在

<script></script>

之間的程式碼是純文字。在core.js執行的時候讀取這段文字,然後動態執行一次。瀏覽器不會執行之間的程式碼

html中的事件處理程式

當指令碼所在的html檔案被載入的時候。指令碼里的js會執行一次。為了可互動,js會定義事件處理程式即web瀏覽器先註冊函式,並在之後呼叫其作為事件的響應。其中事件處理程式的屬性可以包含任意條js語句。相互之間用逗號分隔。該語句會成為一個函式體,然後這個函式體成為對應事件處理程式屬性的值。

url中的js

應用用途 書籤
通過協議型別指定url內容為任意字串,該字串是會被js直譯器執行的js程式碼,其會被當成單獨的一行程式碼實現。即語句之間必須使用分號作為分割。
即,書籤的實現。如果書籤是javascript:url,那麼將會儲存一小段指令碼。該指令碼是一個小型程式,即可以在瀏覽器選單或工具欄裡啟動。該程式碼執行會像頁面上的指令碼一樣,查詢和設定文件的內容,呈現和行為(不能有返回值,會重新促使瀏覽器渲染)即通過書籤,操作文件,將文件替換成為新的內容

js程式的執行

這些程式碼都會功用同一個全域性window物件。即都能共享全域性函式和全域性變數的集合。即一個頁面中js都會在執行後對所有的全域性變數和函式都可見。
如果使用的窗體,

<iframe>

即這兩個頁面共享的不是同一個window,會被當做獨立於頁面的js程式。

js程式執行的階段

一階段

載入文件內容,執行所有指令碼,一般是從上到下的

二階段

文件載入完畢,所有指令碼執行完畢。js進入第二階段,該階段為非同步,由事件驅動。web會呼叫事件處理程式,對事件進行處理。一般事件會是使用者輸入,鍵盤輸入,網路活動,執行時間等等。
事件驅動的第一個事件,即第一個被執行的事件為load事件。

js的同步,非同步和延遲指令碼

因為載入文件和執行指令碼是一併執行的,所以在第一次執行指令碼的時候,會沒有api來操作文件,和遍歷內容。在文件載入的時候,影響文件內容的方法為快速生成內容。

document.write() 將字串寫入document.write()開啟的文件流

一個例子

<h1>計算階乘</h1>
<script>
    function factorial(n) {    // 一個計算階乘的函式,用遞迴實現
        if (n <= 1)
            return n;
        else
            return n * factorial(n-1);    
    }

    document.write("<table border=1>");
    document.write("<tr><th>n</th><th>n!</th></tr>");
    for(var i = 1; i <= 10; i++) {
        document.write("<tr><td>" + i + "</td><td>" + factorial(i) + "</td></tr>");
    }
    document.write("</table>");
    document.write("生成時間為" + new Date());
</script>

這樣在載入的時候完成了頁面文件的修改,並輸出。為1996年的技術
╮(╯▽╰)╭
當指令碼把檔案傳遞給document.write()的時候,該文字會被新增到文件的輸入流中,html解析器會在當前位置建立一個文字節點,將文字插入這個文字節點後面。當html的解析器遇到script元素的時候,預設先執行指令碼,再恢復文件的解析和渲染。但是如果是src的話,將會導致,指令碼未下載和執行之前,都不會出現在dom樹中。都會等待js的指令碼執行。稱之為阻塞頁面ui的渲染。
指令碼執行預設情況下是同步和阻塞的。

 script 有兩個屬性,h5中,為async 以及 defer 該兩個屬性可以支援非同步執行js指令碼。因此這樣瀏覽器將會在下載指令碼的時候繼續解析和渲染文件。可以達到延遲指令碼的執行,直到文件載入和解析完成,才方可操作。不會出現js阻塞頁面ui的渲染。非同步的時候執行是無序。

事件驅動的js

js還能通過註冊事件程式函式寫程式。之後在發生該事件的時候非同步呼叫這些函式。
程式會響應一個事件,然後呼叫一個函式,該函式稱為事件處理程式,事件監聽器,或者回撥,將該函式註冊。

 一個約定,事件處理程式一般是on開頭的

舉例

window.onload = function() {};
document.getElementById('button1').onclick = function(){};

在發生onload事件的時候,回撥第一個函式,在發生點選button1的時候回撥第二個函式。

冒泡

如果事件的目標是文件元素,如果該文件元素沒有相應的處理事件,將會往上傳遞文件樹,知道遇到註冊的事件。這個過程稱之為冒泡。

addeventListener

// 註冊函式f, 當文件載入完成時執行這個函式f
// 如果文件載入完成,將會用非同步的方式執行
function onload(f) {
    if (onload.loaded)    // 如果文件以及載入完成
        window.setTimeout(f, 0);    // 設定一個定時器,放入js執行的佇列中,等待執行
    else if (window.addEventListener)    // 將事件進行註冊
        window.addEventListener("load", f, false) // 註冊事件 load, 當載入完成以後執行函式f,
}
// 設定標誌,指示文件是否載入完成
onload.loaded = false; // 表明未載入完成,
// 註冊函式,當文件載入完成時載入標誌
onload(() => {onload.loaded = true;});

// 大概解釋一下,首先定義了一個函式,設定了一個載入的標誌,在載入的過程中,設定loaded的值為false,當載入完成以後,執行onload函式,將其內部定義的函式傳入onload中,和load事件進行繫結。等待文件載入完成,觸發一個匿名函式,將onload.loaded的值改為true,此時再次傳入的函式f將會返回js的執行佇列中,等待執行。

將一個監聽器和回撥函式繫結,當監聽器被觸發的時候,回撥函式將會被觸發。

客戶端js執行緒模型

js的客戶端為單執行緒模型。
h5中有一種併發的控制方式,為web worker 為一個後臺執行緒,允許執行緒裡的程式碼訪問文件的內容。不能和主執行緒或者其他worker共享狀態,只可進行非同步事件進行通訊。

客戶端js時間線

  1. web瀏覽器先建立document物件,並且開始解析web頁面,(即根節點),解析html元素和其文字內容都會新增到其後方的節點中
  2. html遇到script元素的時候,先執行內部指令碼,等待內部指令碼執行完畢後,在繼續解析html節點,此時節點解析會暫停。可以使用document.write()實現將文字插入流中。解析器恢復解析的時候,該文字會正式的成為文件的一部分,但是頁面的原始碼中並不存在該內容。該操作此時是同步的,可以達到遍歷和操作文件樹的目的。因為在執行的時候,其上方的文件樹就已經存在。
  3. 遇到async屬性的時候會邊下載,邊進行解析html。非同步的時候禁止使用document.write,因為此時指令碼無法插入文件流中。非同步的時候,解析是隨意的。也不清楚什麼時候指令碼會解析。
  4. 文件解析完成。document.readyState將會變成interactive,之前一直為loading狀態。此時表明解析完成
  5. 所有有defer屬性的指令碼,會在此時執行,此時能訪問完成的文件樹,但是禁止使用document.write()因為此時文件樹已經固定
  6. 瀏覽器進入非同步事件驅動階段。此時可能還沒有非同步指令碼執行完成。
  7. 此時文件全部解析完成,但瀏覽器可能在等待圖片的載入,等所有的非同步指令碼全部完成載入和非同步執行的時候,將會觸發load事件,表明全部執行完成,readState將會改為complete
  8. 此刻呼叫非同步事件,響應使用者輸入事件,網路事件,計時器事件。

相容

ie條件註釋

儘管現在相容不是那麼嚴重了,ie也淘汰了,edge上臺了。但還是說一下吧

<!-- [if IE]>
<script src="excanvas">
</script>
<![endif]-->

ie支援條件註釋,上方是使用條件註釋的,在ie下,將會執行上方的js指令碼
通過

@_jscript

可以判斷是不是ie,因為該變數在ie中圓圓為true
寫法如下,用於ie的
使用條件註釋來寫

/*@cc_on
    @if (@_jscript)
        // 書寫相容的ie程式碼,在ie下會被執行,
        alert("in ie")  // 發出警告
    @end

再ie下也會進行執行。
總結 一下

/*@*cc_on
    @if(@_jscript)
        // 這裡的程式碼儘管被註釋,也會執行在ie中
        // ie會執行這段程式碼,其他瀏覽器不會執行
        alert('ie')
    @else*/
        // 這段程式碼並沒有在js註釋中,但仍然在ie條件註釋中。
        // 除了ie之外都會執行
        alert("not ie")
/*@end
@*/

處理相容的類和庫

exanvas.js

功能測試

使用if進行測試,是否實現了

怪異模式和標準模式

使用標準模式就行了
記的加上h5的宣告

瀏覽器測試

可以根據頭部資訊,web伺服器返回響應的js程式碼

部落格

www.iming.info

相關文章