維基百科對它的解釋是:事件驅(qū)動程序設(shè)計(英語:Event-driven programming)是一種電腦程序設(shè)計模型。這種模型的程序運行流程是由用戶的動作(如鼠標的按鍵,鍵盤的按鍵動作)或者是由其他程序的消息來決定的。相對于批處理程序設(shè)計(batch programming)而言,程序運行的流程是由程序員來決定。批量的程序設(shè)計在初級程序設(shè)計教學(xué)課程上是一種方式。然而,事件驅(qū)動程序設(shè)計這種設(shè)計模型是在交互程序(Interactive program)的情況下孕育而生的。
簡頁言之,在 web 前端編程里面 JavaScript 通過瀏覽器提供的事件模型 API 和用戶交互,接收用戶的輸入
由于用戶的行為是不確定的,也就是說不知道用戶什么時候發(fā)生點擊、滾動這些動作。這種場景是傳統(tǒng)的同步編程模型沒法解決的,因為你不可能等用戶操作完了才執(zhí)行后面的代碼
比如我們在 Python 里面調(diào)用接收用戶輸入的方法 raw_input() 后終端就會一直等待用戶的輸入,直到輸入完成才會執(zhí)行后面的代碼邏輯。但是在下面這段 NodeJS 代碼中,接收用戶輸入的方法 process.stdin.read 是在一個事件中調(diào)用的。后面的代碼不會被阻塞(blocked)。
事件驅(qū)動程序模型基本的實現(xiàn)原理基本上都是使用 事件循環(huán)(Event Loop),這部分內(nèi)容涉及瀏覽器事件模型、回調(diào)原理,有興趣的去看鏈接里面的視頻學(xué)習(xí)下
需要說明的是在客戶端 JavaScript 中像 setTimeout, XMLHTTPRequest 這類 API 并不是 JavaScript 語言本身就有的。而是 JavaScript 的宿主環(huán)境(在客戶端 JavaScript 中就是瀏覽器),同樣像 DOM、BOM、Event API 都是瀏覽器提供的
事件綁定的方法
DOM 元素行內(nèi)綁定
直接在 DOM 元素上通過設(shè)置 on + eventType 來綁定事件處理程序
這種綁定方法是最原始的,有兩個缺點:
1 事件處理程序和 HTML 結(jié)構(gòu)混雜在一起
早期在結(jié)構(gòu)、樣式、表現(xiàn)分離的時代很忌諱這一點。現(xiàn)在看來在很多 MVX 框架中將事件綁定和 DOM 結(jié)構(gòu)放在一起處理,這樣似乎更方便維護(不用來回切換 HTML,JavaScript 文件),而且也符合可預(yù)見(predictable)性的規(guī)則
2 命名空間沖突
因為 onclick 中的 JavaScript 代碼片段執(zhí)行環(huán)境是全局作用域。然而在 JavaScript 語言中并沒有相關(guān)的命名空間特性。所以就很容易造成命名空間的沖突,非要用這種方法綁定事件的話只能用對象來做一些封裝。
現(xiàn)代/標準的綁定方法
標準的綁定方法有兩種,addEventListener 和 attachEvent 前者是標準瀏覽器支持的 API,后者是 IE 8 以下瀏覽器支持的 API。通常需要我們做個兼容封裝:
<script>
function addEvent(target, type, handler) {
if (target.addEventListener) {
target.addEventListener(type, handler, false);
} else {
target.attachEvent('on' + type, handler)
}
}
addEvent(document, 'click', function() { alert(this === document) });
addEvent(document, 'click', function() { alert(this === document) });
</script>
上面的例子在 IE 8 以下和標準瀏覽器的效果是不一樣的,問題就在于 addEventListener中的事件回調(diào)函數(shù)中的 this 指向元素(target)本身,而 attachEvent 則指向 window 為了修復(fù)這個問題上面的 attachEvent 可以做一點小調(diào)整讓其保持和 addEventListener 的效果一樣,不過這樣的話注冊的 handler 就是個匿名函數(shù),無法移除!