(92)Wangdao.com_第二十五天_線程機制_H5 Web Workers 分線程任務_事件 Event

瀏覽器內核css

支撐瀏覽器運行的最核心的程序html

  • IE 瀏覽器內核            Trident內核,也是俗稱的IE內核
    Chrome 瀏覽器內核            統稱爲 Chromium 內核或 Chrome 內核,之前是 Webkit 內核,如今是 Blink 內核
    Firefox 瀏覽器內核            Gecko 內核,俗稱 Firefox 內核
    Safari 瀏覽器內核            Webkit 內核
    Opera 瀏覽器內核            最初是本身的 Presto 內核,後來是 Webkit,如今是 Blink 內核編程

  • 360瀏覽器、獵豹瀏覽器內核:IE+Chrome雙內核;
    搜狗、遨遊、QQ瀏覽器內核:Trident(兼容模式)+Webkit(高速模式);
    百度瀏覽器、世界之窗內核:IE內核;
    2345瀏覽器內核:之前是IE內核,如今也是IE+Chrome雙內核;數組

  • 瀏覽器的事件循環模型(輪詢)——主線程,分線程 協做執行

主線程,從上而下執行代碼,將代碼產生的相關任務分配給對應的分線程瀏覽器

分線程 每當有 事件回調函數 在知足必定條件後,加入回調隊列的末尾網絡

js 執行完全部代碼之後,js  開啓輪詢,會不斷地 輪詢回調隊列,執行隊列中的回調函數多線程

  • 執行棧: 全部代碼都在 這個空間 中執行
  • 回調隊列,遵循先進先出
  • 任務隊列 task queue消息隊列 message queue事件隊列 event queue——都是指的 callback queue 回調隊列
  • 事件輪詢 event loop : 從任務隊列中循環取出回調函數放入 執行棧 中執行
  • 事件驅動模型: event-driven interaction model
  • 請求響應模型: request-response model

  • 由許多模塊組成:

主線程:異步

js 引擎模塊            負責 js 程序的編譯與運行ide

html/css 文檔解析模塊            負責 頁面文本 的解析異步編程

DOM/CSS 模塊            負責 DOM 和 css 在內存中的處理

佈局和渲染模塊            負責頁面的佈局和效果的繪製(內存中的對象)

分線程:

定時器模塊            負責定時器的管理

DOM事件響應模塊            負責事件的管理

網絡請求模塊            負責 AJAX 的請求  

進程

程序的一次執行,佔有一片獨有的內存空間

單進程

多進程,同一時間可作多件事

線程

調度 CPU 執行具體程序,是CPU的最小調度單元

是進程內的一個獨立執行單元

應用程序必須運行在某個進程的某個線程上

一個進程至少有一個運行的線程——主線程,進程啓動後自動建立

一個進程內的數據 是能夠被多個線程直接共享的

進程與進程之間的數據是不共享的

線程池: 保存多個線程對象的容器,實現線程對象的反覆利用

  • 1. 單線程 優勢: 順序編程簡單易懂
  • 2. 單線程 缺點: 效率低
  • 3. 多線程 優勢: 能有效提高 CPU 的利用率
  • 4. 多線程 缺點: 建立多線程開銷,線程切換開銷,產生死鎖和狀態同步的問題
  • 瀏覽器 js 引擎 開啓了一個進程,該進程有且只有一個線程
  • IE 最開始是 單進程的,速度慢,可是事件的處理更簡單,某個頁面崩潰,整個瀏覽器都崩潰了。
  • 現代瀏覽器 大多都是 多進程的,速度快,每一個頁面都是單獨的進程,彼此互不影響。
  • 瀏覽器是有些是單進程,有些是多進程的。可是必定是多線程的——使用任務管理器查看
  • js 是單線程的,alert 會中止繼續運行。
  • 但使用 H5 中的 Web Workers 能夠多線程運行

 

H5 規範提供了 js 分線程——Web Workers 

需求: 主線程 若是再進行大量計算任務時,沒法執行其餘任務

1. index.js 使用分線程

  • var newWorker = new Worker(./worker.js);    // 開啓一個分線程
    
    // 綁定接受分線程消息的事件
    newWorker.onmessage = function(e){
        console.log("分線程: "+e.data);
    };
    
    btn.onclick = function(){
        newWorker.postMessage(number.value);    // 主線程 通知分線程 開始執行
    };

 

2. worker.js 寫 分線程 接收主線程發送的消息

  • var onmessage = function(event){
        // 接收消息的回調函數 event
        var data = event.data;
        var result = fibonacci(+data); // 計算
        postMassage(result);
    };

    function fibonacci(num){
    return (num < 3)?1:(fabonacci(num-1)+fabonacci(num-2));
    }

 

1. 事件 Event

事件的本質是: 程序各個組成部分之間的一種通訊方式,也是 異步編程 的一種實現

DOM 的事件操做 分爲: 監聽 觸發        都定義在 EventTarget 接口____

全部節點對象都部署了 EventTarget 接口,其餘一些須要事件通訊的瀏覽器內置對象(好比,XMLHttpRequest、AudioNode、AudioContext)也部署了這個接口。

.addEventListener();        綁定事件的監聽函數

.removeEventListener();        移除事件的監聽函數

.dispatchEvent();        觸發事件

 

  • EventTarget.addEventListener(eventType, listener[, useCapture]);

用於在當前節點或對象上,定義一個特定事件的監聽函數。

一旦這個事件發生,就會執行監聽函數。

能夠爲針對當前對象的同一個事件,添加多個不一樣的監聽函數。這些函數按照添加順序觸發,即先添加先觸發。

若是爲同一個事件屢次添加同一個監聽函數,該函數只會執行一次,多餘的添加將自動被去除(沒必要使用removeEventListener方法手動去除)。

  • 該方法沒有返回值
  • 參數: 

eventType        事件名稱,大小寫敏感。

listener        監聽函數。事件發生時,會調用該監聽函數。

  • 注意: 
  • 除了監聽函數,還能夠是一個 具備 handleEvent 方法的對象
  • btn.addEventListener('click',   {
                                        handleEvent: function (event) {
                                            console.log('click');
                                        }
                                    }, false);

[useCapture]        是否在捕獲階段(capture)觸發(參見後文《事件的傳播》部分)默認爲 false(監聽函數只在冒泡階段被觸發)。該參數可選

  • 注意: 
  • 除了布爾值 useCapture,還能夠是一個屬性配置對象
  • 該對象有如下屬性:

capture: 布爾值,表示該事件是否在捕獲階段觸發監聽函數。

once: 布爾值,表示監聽函數是否只觸發一次,而後就自動移除。

passive: 布爾值,表示監聽函數不會調用事件的 preventDefault 方法。默認爲 true 若是監聽函數調用了,瀏覽器將忽略這個要求,並在監控臺輸出一行錯誤。

  • 但願事件監聽函數只執行一次,能夠打開屬性配置對象的once屬性
  • ele.addEventListener('click', function (event) {
      // 只執行一次的代碼
    }, {once: true});
  • 若是但願向監聽函數傳遞參數,能夠用匿名函數包裝一下監聽函數
  • var box = document.getElementById('div1');
    box.addEventListener('click', function () {
        myPrint('Hello'); 
    }, false);
    
    function myPrint(x) {
        console.log(x);
    }
  • EventTarget.removeEventListener(eventType, listener);

用來移除 .addEventListener() 方法添加的事件監聽函數。

該方法沒有返回值

listener 在綁定時是 匿名函數,那麼將沒法直接用 .removeEventListener() 移除。

 

  • EventTarget.dispatchEvent(Event對象的實例)

在當前節點上觸發指定事件,從而觸發監聽函數的執行。

  • 返回一個布爾值

只要有一個監聽函數調用了 Event.preventDefault(),則返回值爲 false,不然爲 true

  • ele.addEventListener('click', hello, false);
    
    var event = new Event('click');
    ele.dispatchEvent(event);    // 主動觸發 click 事件

     

2. 瀏覽器的事件模型

就是經過監聽函數(listener)對事件作出反應。

事件發生後,瀏覽器監聽到了這個事件,就會執行對應的監聽函數。

____這是事件驅動編程模式(event-driven)的主要編程方式

  • 綁定事件監聽函數的三種方法:

在 html 標籤 中直接綁定

  • 只會在冒泡階段觸發
  • 缺點: 違反了 HTML 與 JavaScript 代碼相分離的原則
  • <body onload="doSomething()">    <!-- 等同於 document.body.setAttribute("onload", "doSomething()"); -->
    <div id="box" onclick="console.log('觸發事件')">    // this 輸出 box

在 js 代碼中,給元素對象 的事件屬性綁定監聽函數

  • 衆所周知的 DOM0 級事件模型 綁定方式,也只會在冒泡階段觸發
  • 缺點: 同一個事件只能定義一個監聽函數,也就是說,若是定義兩次onclick屬性,後一次定義會覆蓋前一次
  • window.onload = doSomething;
    
    div.onclick = function (event) {
        console.log('觸發事件');
    };

使用 EventTarget.addEventListener() 綁定

  • 衆所周知的 DOM2 級事件模型 綁定方式
  • window.addEventListener('DOMContentLoaded', doSomething, false);
  • 優勢:

除了 DOM 節點,其餘對象(好比window、XMLHttpRequest等)也有這個接口,等因而整個 JavaScript 統一的監聽函數接口

可以指定在哪一個階段(捕獲階段仍是冒泡階段)觸發監聽函數

同一個事件能夠添加多個監聽函數

 

3. 事件的傳播

使得同一個事件會在多個節點上觸發

  • 分紅三個階段

「捕獲階段」(capture phase)        從 window 對象 傳導到 目標節點
「目標階段」(target phase)        在目標節點上觸發
「冒泡階段」(bubbling phase)        從 目標節點 傳導回 window對象

  • var phases = {
        1: 'capture',
        2: 'target',
        3: 'bubble'
    };
    
    var div = document.querySelector('div');
    var p = document.querySelector('p');
    
    div.addEventListener('click', callback, true);
    div.addEventListener('click', callback, false);
    
    p.addEventListener('click', callback, true);
    p.addEventListener('click', callback, false);
    
    function callback(event) {
        console.log("Tag: " + event.currentTarget.tagName,
                    "EventPhase: " + phases[event.eventPhase]);
    };
    
    // 點擊之後的結果
    // Tag: 'DIV'. 
    // EventPhase: 'capture'
    
    // Tag: 'P'
    // EventPhase: 'target'
    
    // Tag: 'P'
    // EventPhase: 'target'
    
    // Tag: 'DIV'
    //EventPhase: 'bubble'
  • 注意:

瀏覽器老是假定 click 事件的目標節點,就是點擊位置嵌套最深的那個節點

事件傳播的最上層對象是window,接着依次是document,html(document.documentElement)和body(document.body)

也就是說,上例的事件傳播順序,

在捕獲階段依次爲window、document、html、body、div、p

在冒泡階段依次爲p、div、body、html、document、window。

  • 事件委派 / 事件代理(delegation)

把子節點的監聽函數定義在父節點上,由父節點的監聽函數統一處理多個子元素的事件

  • 優勢:

只要定義一個監聽函數,就能處理多個子節點的事件,而不用在每一個<li>節點上定義監聽函數

並且之後再添加子節點,監聽函數依然有效

  • 若是但願事件到某個節點爲止,再也不傳播,可使用事件對象的 event.stopPropagation() 方法

可是,stopPropagation方法只會阻止事件的傳播,

不會阻止該事件觸發 <p> 節點的其餘 click 事件的監聽函數。

也就是說,不是完全取消click事件

  • p.addEventListener('click', function (event) {
      event.stopPropagation();
      console.log(1);    // 不會觸發
    });
    
    p.addEventListener('click', function(event) {
      // 會觸發
      console.log(2);
    });
  • 若是想要完全取消該事件再也不觸發後面全部click的監聽函數,可使用 event.stopImmediatePropagation() 方法

 

4. Event 對象

Event 對象自己就是一個構造函數,能夠用來生成新的實例

 

  • event = new Event(type, options);

接收兩個參數: 

  • type        字符串,表示 事件的名稱
  • options        對象,表示 事件對象的配置。

該對象主要有下面兩個屬性

  • bubbles        布爾值,可選,默認爲 false,表示事件對象是否冒泡

若是不是顯式指定 bubbles 屬性爲 true,生成的事件就只能在 「捕獲階段」 觸發監聽函數

  • cancelable        布爾值,可選,默認爲false,表示事件是否能夠被取消

即可否用 event.preventDefault() 取消這個事件。

一旦事件被取消,就好像歷來沒有發生過,不會觸發瀏覽器對該事件的默認行爲

  • 實例屬性

Event.bubbles

表示當前事件是否會冒泡。

返回一個布爾值,除非顯式聲明,Event構造函數生成的事件,默認是不冒泡的。

該屬性爲只讀屬性,用來判斷 Event 實例是否能夠冒泡

Event.eventPhase

表示事件目前所處的階段。

返回一個整數常量,該屬性只讀

  • 0,事件目前沒有發生。
    1,事件目前處於捕獲階段,即處於從祖先節點向目標節點的傳播過程當中。
    2,事件到達目標節點,即 Event.target 屬性指向的那個節點。
    3,事件處於冒泡階段,即處於從目標節點向祖先節點的反向傳播過程當中。

Event.cancelable

表示事件是否能夠取消。

返回一個布爾值,該屬性爲只讀屬性,

通常用來判斷 Event 實例是否能夠被取消

  • 當 Event.cancelable 屬性爲true 時,調用 Event.preventDefault(); 就能夠取消這個事件,阻止瀏覽器對該事件的默認行爲。
  • 若是事件不能取消,調用 Event.preventDefault() 會沒有任何效果。
  • 因此使用這個方法以前,最好用 Event.cancelable 屬性 判斷一下是否能夠取消
  • /**** 封裝 禁止瀏覽器默認行爲 ****/
    function
    preventEvent(event) { if (event.cancelable) { event.preventDefault(); } else { console.warn('This event couldn\'t be canceled.'); console.dir(event); } }

Event.cancelBubble

阻止事件的傳播。        若是設爲true,至關於執行Event.stopPropagation()

是一個布爾值

Event.defaultPrevented

表示該事件是否調用過 Event.preventDefault() 方法。

返回一個布爾值,該屬性只讀。

Event.currentTarget

返回 事件當前所在的節點,即正在執行的監聽函數所綁定的那個節點,隨事件傳播過程而變化

Event.target

返回 原始觸發事件的那個節點,即事件最初發生的節點,事件傳播過程當中是固定不變的

Event.type

表示事件類型。

返回一個字符串,事件的類型是在生成事件的時候。

該屬性只讀

Event.timeStamp

返回一個毫秒時間戳,表示事件發生的時間。

它是相對於網頁加載成功開始計算的。

  • 實例計算鼠標移動速度,每秒移動的 px 值
  • var previousX;
    var previousY;
    var previousT;
    
    window.addEventListener('mousemove', function(event) {
        if (previousX !== undefined &&
            previousY !== undefined &&
            previousT !== undefined ){
            var deltaX = event.screenX - previousX;    // 獲取  當前的 xOffset
            var deltaY = event.screenY - previousY;    // 獲取  當前的 yOffset
            var deltaD = Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
    
            var deltaT = event.timeStamp - previousT;
            console.log(deltaD / deltaT * 1000);    // 速度 = 路程 / 時間
        };
    
        previousX = event.screenX;    // 獲取移動前的 x
        previousY = event.screenY;    // 獲取移動前的 y
        previousT = event.timeStamp;    // 獲取當前時間戳
    });

Event.isTrusted

表示該事件是否由真實的用戶行爲產生。

返回一個布爾值

好比,用戶點擊連接會產生一個 click 事件,該事件是用戶產生的;Event 構造函數生成的事件,則是腳本產生的。

Event.detail

該屬性返回一個數值,表示事件的某種信息。

只有瀏覽器的 UI (用戶界面)事件才具備此屬性。

具體含義與事件類型相關。

好比,

對於 click 和 dbclick 事件,Event.detail 是鼠標按下的次數(1表示單擊,2表示雙擊,3表示三擊);

對於鼠標滾輪事件,Event.detail 是滾輪正向滾動的距離,負值就是負向滾動的距離,返回值老是 3 的倍數。

  • 實例方法

Event.preventDefault()

取消瀏覽器對當前事件的默認行爲。

好比點擊連接後,瀏覽器默認會跳轉到另外一個頁面,使用這個方法之後,就不會跳轉了;

再好比,按一下空格鍵,頁面向下滾動一段距離,使用這個方法之後也不會滾動了。

再好比,瀏覽器的默認行爲是單擊會選中單選框,取消這個行爲,就致使沒法選中單選框

該方法生效的前提是,事件對象的 cancelable 屬性爲true,若是爲 false,調用該方法沒有任何效果

注意,該方法只是取消事件對當前元素的默認影響,不會阻止事件的傳播。

若是要阻止傳播,可使用 event.stopPropagation() 或 event.stopImmediatePropagation() 方法

  • 實例: 爲文本輸入框設置校驗條件。若是用戶的輸入不符合條件,就沒法將字符輸入文本框。
  • // HTML 代碼爲
    // <input type="text" id="my-input" />
    var input = document.getElementById('my-input');
    input.addEventListener('keypress', checkName, false);
    
    function checkName(e) {
        if (e.charCode < 97 || e.charCode > 122) {
            e.preventDefault();
        }
    }

    上面代碼爲文本框的 keypress 事件設定監聽函數後,將只能輸入小寫字母,不然輸入事件的默認行爲(寫入文本框)將被取消,致使不能向文本框輸入內容

Event.stopPropagation()

阻止事件在 DOM 中繼續傳播,防止再觸發定義在別的節點上的監聽函數,

可是不包括在當前節點上其餘的事件監聽函數

Event.stopImmediatePropagation()

阻止同一個事件的全部監聽函數被調用,無論監聽函數定義在當前節點仍是其餘節點。

也就是說,該方法阻止事件的傳播,比Event.stopPropagation()更完全

Event.composedPath()

返回一個節點數組,成員是事件的最底層節點依次冒泡通過的全部上層節點

相關文章
相關標籤/搜索