標籤:attach handle 文法 之間 版本 請求 listen note trigger
1、什麼是非同步(Asynchronous)編程?
相對於同步(Synchronous)而言,非同步就是後一個任務不需要等待前一個任務結束就執行,而前一個任務結束以後執行回呼函數。
最常見的非同步編程有setTimeout函數、 ajax請求等。
如:
for (var i = 1; i <= 3; i++) {
setTimeout(function(){
console.log("#",i);
}, 0);
console.log("*",i);
};
輸出的結果是:*1 *2 *3 #4 #4 #4
涉及到的知識點: 非同步、閉包、範圍
setTimeout是一個註冊事件,在主程式運行結束前,是不會調用的。
就像為某個div綁定一個點擊事件一樣,在沒點擊之前,這個事件是不會被觸發的。
這就是一個常見的非同步編程的例子。
2、非同步編程的方法
Ⅰ、回呼函數
假設有 f1(); f2(); 兩個函數,其中f2()在等待f1()的執行結果。
function f1(f2){
setTimeout(function(){
f2();
}, 1000);
}
代碼執行順序:f1(f2);
優點:f1不會堵塞程式運行,相當於先執行程式的主要邏輯,將耗時的操作延遲執行
缺點:不利於代碼的閱讀和維護,各個部分之間高度耦合(Coupling),而且每個任務只能指定一個回呼函數
Ⅱ、事件監聽
f1.on(‘done‘, f2);//jQuery寫法,當f1發生done事件,就執行f2
function f1(){
setTimeout(function () {
f1.trigger(‘done‘);//執行完成後,立即觸發done事件
}, 1000);
}
優點:可以綁定多個事件,每個事件可以指定多個回呼函數,而且可以"去耦合"(Decoupling),有利於實現模組化
缺點:整個程式都要變成事件驅動型,運行流程會變得很不清晰
Ⅲ、發布/訂閱
jQuery.subscribe("done", f2);//f2向jQuery訂閱"done"訊號
function f1(){
setTimeout(function () {
jQuery.publish("done");//f1執行完成後,向jQuery發布"done"訊號,從而引發f2的執行
}, 1000);
}
Ⅳ、Promises對象
它的思想是,每一個非同步任務返回一個Promise對象,該對象有一個then方法,允許指定回呼函數。比如,f1的回呼函數f2,可以寫成:
f1().then(f2);
對f1進行如下改寫:
function f1(){
var dfd = $.Deferred();
setTimeout(function () {
dfd.resolve();
}, 500);
return dfd.promise;
}
優點:回呼函數變成了鏈式寫法,程式的流程可以看得很清楚,可以指定多個回呼函數,如:
f1().then(f2).then(f3);
f1().then(f2).fail(f3);
缺點:編寫和理解,都相對比較難
附幾個概念:
一、事件
事件就是文檔或瀏覽器視窗中發生的一些特定的互動瞬間。
二、註冊事件
註冊事件分為屬性註冊和方法註冊。
屬性註冊:1.內嵌在DOM結構裡的屬性賦值
HTML: <button onclick="sayHello()">點擊</button>
JS: function sayHello() {
console.log(‘hello‘)
}
2.通過JS來指定元素對象的屬性賦值
document.body.onclick = function (e) {
alert("為body註冊一個點擊事件");
};
方法註冊:1.通過addEventListener()方法註冊
說明:在JS中,window、document、HtmlElement等對象可以通過addEventListener()方法註冊事件的處理常式。
文法:EventTarget.addEventListener(eventName, eventHandler, |useCapture )
參數:
①eventName {string} :所要註冊的事件名稱,不區分大小寫。此名稱不需要像註冊事件屬性那樣首碼加上"on"。如註冊滑鼠點擊事件,寫為click。
②eventHandler {function | function Object} :函數或者函數對象。事件觸發時所需要執行的函數;當使用函數對象多次註冊同一事件時,只當註冊一遍。
③useCapture {boolean} 可選 :是否處於捕獲階段,預設為false。
多次註冊:addEventListener()方法能為同一個對象的同一事件註冊多次。當發生此事件時,註冊的處理事件程式將按照註冊先後順序執行。
注意:
①IE9之前的IE的不支援此方法,可使用attachEvent()代替。
②若使用相同的事件處理常式對象多次註冊在同一個事件上,只算註冊一次。
例:
document.body.addEventListener(‘click‘,function(e){
console.log(‘被點擊一‘);
});
document.body.addEventListener(‘click‘,function(e){
console.log(‘被點擊二‘);
});
document.body.click(); // 輸出: 被點擊一 被點擊二
2.通過attachEvent()方法註冊
說明:IE9之前的IE版本可通過此方法註冊事件。
文法:EventTarget.attachEvent(eventName, eventHandler)
①eventName {string} :所要註冊的事件名稱,區分大小寫。這裡的名稱跟事件屬性一樣,以"on"開頭,後面跟著事件名稱。如:onclick、onload。
②eventHandler {function | function Object} :函數或者函數對象。事件觸發時所需要執行的函數;當使用函數對象多次註冊同一事件時,可註冊多次(addEventListener()方法只當註冊一次)。
多次註冊:attachEvent()方法能為同一個對象的同一事件註冊多次。當觸發此事件時,也會依次執行。
例:
function sayHellow(){
console.log(‘hello‘);
}
document.body.attachEvent(‘onclick‘,sayHellow);
document.body.attachEvent(‘onclick‘,sayHellow); // sayHellow第二次註冊同一事件
document.body.click(); //輸出2次sayHellow函數 :hello hello
二、登出事件
JS中,可調用removeEventListener()[登出addEventListener()] 和 detachEvent()[登出attachEvent()] 來登出元素的某個事件指定的處理常式,也可以給事件屬性賦值null來登出此事件的所有綁定。
1.removeEventListener(eventName, function Object)
說明:登出通過addEventListener()註冊的事件處理常式。
文法:EventTarget.removeEventListener(eventName, eventHandlerObj)
參數:
①eventName {string} :所要登出的事件名稱,不區分大小寫。此名稱不需要像註冊事件屬性那樣首碼加上"on"。如註冊滑鼠點擊事件,寫為click。
②eventHandlerObj {function Object} :函數對象。傳入一個函數體是沒有效果的。
例:
// 登出body click事件的sayHello函數
document.body.removeEventListener(‘click‘,sayHello);
2.detachEvent(eventName, function Object)
說明:登出通過attachEvent()註冊的事件處理常式。
文法:EventTarget.detachEvent(eventName, eventHandlerObj)
參數:
①eventName {string} :所要登出的事件名稱,區分大小寫。這裡的名稱跟事件屬性一樣,以"on"開頭,後面跟著事件名稱。如:onclick、onload。
②eventHandlerObj {function Object} ::函數對象。傳入一個函數體是沒有效果的。
例:
// 登出body click事件的sayHello函數
document.body.detachEvent(‘onclick‘, sayHello);
3.取消事件
給對象的事件屬性賦值為null,可取消此事件的所有註冊過的處理事件程式。
例:
// onclick屬性賦值為null,相當於登出了onclick事件
document.body.onclick=null;
參考連結:http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html
http://www.qdfuns.com/notes/17398/e8a1ce8f863e8b5abb530069b388a158/page/.html
Javascript非同步編程