天天看點

js的三大事件、事件移除、事件循環機制

什麼是事件,三種事件模型

事件是使用者操作網頁時發生的互動動作或者網頁本身的一些操作。

現代浏覽器一共有三種事件模型:

  • DOM0 級事件模型,這種模型不會傳播,是以沒有事件流的概念,但是現在有的浏覽器支援以冒泡的方式實作,它可以在網頁中直接定義監聽函數,也可以通過 js 屬性來指定監聽函數。所有浏覽器都相容這種方式。

    直接在 dom 對象上注冊事件名稱,就是 DOM0 寫法

  • IE 事件模型,在該事件模型中,一次事件共有兩個過程,事件處理階段和事件冒泡階段。

    事件處理階段會首先執行目标元素綁定的監聽事件。

    然後是事件冒泡階段,冒泡指的是事件從目标元素冒泡到document,依次檢查經過的節點是否綁定了事件監聽函數,如果有則執行。

    attachEvent就是IE事件模型

    ,attachEvent用來添加監聽函數,可以添加多個監聽函數,會按順序依次執行。
  • DOM2 級事件模型,在該事件模型中,一次事件共有三個過程,

    第一個過程是事件捕獲階段。捕獲指的是事件從 document 一直向下傳播到目标元素,依次檢查經過的節點是否綁定了事件監聽函數,如果有則執行。後面兩個階段和 IE 事件模型的兩個階段相同。

    addEventListener 就是DOM2級事件模型

三大事件(滑鼠事件、鍵盤事件、html事件)

1、滑鼠事件

  • click:單擊
  • dblclick:輕按兩下
  • mousemove:滑鼠移動
  • mousedown:滑鼠按下
  • mouseup:滑鼠擡起
  • mouseover:滑鼠懸浮
  • mouseout:滑鼠離開
  • mouseenter:滑鼠進入
  • mouseleave:滑鼠離開

2、鍵盤事件

  • keydown:按鍵按下
  • keyup:按鍵擡起
  • keypress:按鍵按下擡起

3、HTML事件

  • load:文檔加載完成
  • select:被選中的時候
  • change:内容被改變
  • focus:得到光标
  • blur:失去光标
  • resize:視窗尺寸變化
  • scroll:滾動條移動

事件委托機制

事件委托指的是,不在事件的發生地設立監聽函數,而是在事件發生地的父元素或者祖先元素設定監聽器函數,這樣可以大大提高性能,因為可以減少綁定事件的元素,比如:

<ul>
  <li></li>
  <li></li>
  <li></li>
</ul>
           

你要給li元素綁定click事件,

使用事件委托機制的話,就隻需要給ul綁定click事件就行了,

這樣就不需要給每個li’綁定click事件,減小記憶體占用,提高效率。

事件的移除

事件的注冊方式對應其移除方式

1、 el.onclick = null

var el = document.getElementById("btn");
//事件注冊
 el.onclick = function(event){  
     alert(id); 
     el.onclick = null;   //事件删除
 }
           

2、el.removeEventListener(type,fn,false); //這裡 fn 必須是原有綁定的函數,否側解除無效

var div = document.getElemetById('id');
div.addEventListener('click',test,false);
function test(){
 console.log('remove click');
}
div.removeEventListener('click',test,false);
           

事件循環機制

0、背景 (

重點!!!!

JavaScript 在設計之初便是單線程,即指程式運作時,隻有一個線程存在,同一時間隻能做一件事

為了解決單線程運作阻塞問題,JavaScript用到了計算機系統的一種運作機制,這種機制就叫做

事件循環(Event Loop)

重點!!!!

既然JS是單線程的,那麼諸如onclick回調,setTimeout,Ajax這些異步都是怎麼實作的呢?

是因為js在浏覽器中執行,而

浏覽器或node是多線程

的,為了解決js單線程運作阻塞問題,

浏覽器搞了幾個異步線程去輔助JS主線程的運作

浏覽器有很多線程,例如:
1、GUI 渲染線程
2、JS 引擎線程
3、定時器觸發線程 (setTimeout)
4、浏覽器事件線程 (onclick)
5、http 異步線程
6、EventLoop輪詢處理線程
......
           

那麼主線程與這些異步線程之間的運作機制,就是

事件循環機制

為什麼要把js設計成單線程 ?

因為JavaScript 初期作為一門浏覽器腳本語言,通常用于操作 DOM ,如果是多線程,一個線程進行了删除 DOM ,另一個添加 DOM,此時浏覽器該如何處理?

1、是什麼

前言:

JavaScript 有一個

主線程和調用棧

,所有的任務最終都會被放到調用棧等待主線程執行。

主線程之外存在一個

任務隊列

,任務隊列中就是異步任務的回調,最終這些回調會被調用棧讀取後放入主線程中運作。

Event Loop 具體過程如下:

1.1, js在執行代碼時,由上至下進行解析;

1.2, 首先,遇到任務,判斷該任務是同步還是異步任務;

1.3, 同步任務會被放在調用棧中,按照順序等待主線程依次執行。

1.4, 如果是異步任務,

開啟異步線程,執行異步任務

( 而主線程繼續執行同步代碼 )

異步任務 執行完後,将其回調函數 放入

相應的任務隊列

(Event Queue)中,而任務隊列分為宏任務隊列與微任務隊列,等待任務的執行。

1.5,調用棧内的任務執行完畢時,此時

主線程處于空閑狀态

,會去 任務隊列 讀取任務,再把它推入主線程執行。(讀取任務隊列中的任務時,優先讀取微任務,後讀取宏任務),執行完一個再去 任務隊列讀取異步任務,把任務放到主線程中執行,如此循環,這就是 JavaScript 的運作機制,稱為

事件循環機制(Event Loop)

總結 js執行順序: 同步函數 ===》微任務 ===》 宏任務

總結:事件循環機制如下:

1、同步代碼,直接執行

2、 異步代碼,開啟異步線程,執行異步代碼,執行完畢後,将其回調函數,放入任務隊列中。

3、待同步函數執行完畢,輪詢執行任務隊列的函數

2、異步任務有哪些,用浏覽器的哪個異步線程執行

  • 1、定時任務:setTimeout、setInterval ---------

    浏覽器定時器線程

  • 2、網絡請求:ajax請求、動态img加載 ---------

    浏覽器http異步線程

  • 3、DOM綁定的事件:dom事件 ---------

    浏覽器事件線程

  • 4、ES6中的promise.then中的函數
Promise 構造函數是同步執行的,promise.then 中的函數是異步執行的。

3、異步線程何時被放入任務隊列?

  • 1、DOM綁定的事件-------- 由

    浏覽器事件線程

    處理,事件觸發時,回調函數添加到任務隊列中;
  • 2、定時任務:---------由

    浏覽器定時器線程

    處理,時間到達時,回調函數添加到任務隊列中;
  • 3、網絡請求 ----------- 由

    浏覽器http異步線程

    處理,網絡請求傳回後,回調函數添加到任務隊列中。
ajax加載完成,即ajax什麼時候success,就什麼時候把ajax中的函數放入到異步隊列中
異步任務又分為 宏觀任務 、微觀任務

4、 異步任務分類: 宏觀任務、微觀任務

  • 宏觀任務包含以下幾類

    定時器----setTimeout、setInterval、

    DOM綁定的事件、

    異步Ajax請求

    檔案操作

  • 微觀任務包含以下幾類—常用的ES6新增的方法

    Promise.then、

    async/await (實際上是promise+generator的文法糖)

    Generator

【參考連結】:https://www.cnblogs.com/yugege/p/9598265.html

【參考連結】:https://mp.weixin.qq.com/s/9iN7XR1PwXfua8SrabOi5w

繼續閱讀