javascript 異步編程

   js 是一種"單線程」(single thread)執行環境的語言,因此在任務執行的過程當中是按照隊列的形式,當一個任務執行完再執行下一個任務,這樣的模式會由於一個任務執行時間較長的時候出現性能問題,例如頁面假死狀態。
爲了解決這個問題,js將執行模式分爲兩種:同步(synchronous)和異步(asynchronous)
   同步執行:後一個任務等待前一個任務執行完畢再執行。
   異步執行:前一個任務可傳入一個回調函數,在執行完畢後調用回調函數,後一個任務不等前一個任務執行完畢就會執行。
   目前我總結的異步編程有一下幾種方式:
  • 回調函數
  • 事件監聽
  • 發佈/訂閱
  • promise
  • async/awaits
1.回調函數
對調函數是最簡單直接的方法,給執行的異步函數傳入一個函數做爲回調函數,當異步返回結果的時候執行回調函數
function cbFun() {
console.log("hello word!");
}
function asyncFun(callback) {
setTimeout(() => {
callback();
}, 3000);
}
 
asyncFun(cbFun);
 
2.事件監聽
另外一種思路採用事件驅動模式,任務的執行不取決於代碼的順序,而取決於事件的是否發生,這裏用eventEmitter3 這個插件來實現
function cbFun() {
console.log("hello word!");
}
function asyncFun() {
setTimeout(() => {
emitter.emit("msg");
}, 3000);
}
var emitter = new EventEmitter3();
emitter.on("msg", cbFun);
// 執行異步函數
asyncFun()

  

這種方法有點比較容易理解,能夠綁定多個事件,每一個事件均可以指定多個回調函數,能夠」去耦合」(decoupling),有利於實現模塊化。缺點是整個程序都要變成事件驅動,運行流程會變的不清晰。
 
3.發佈/訂閱
咱們能夠把事件驅動看做成信號驅動,咱們假定存在一個」信號中心「,某個任務完成就會去信號中心發佈一個信號,其餘任務能夠在信號中心訂閱這個信號,從而指導本身何時開始執行,這種模式叫作」發佈/訂閱模式「(publish-subscribe pattern).下面是一種實現發佈訂閱模式的對象
var PubSub = function() {
this.list = {};
};
//給訂閱者提供訂閱的方法
PubSub.prototype.subscribe = function(key, callback) {
if (!this.list[key]) {
this.list[key] = [];
}
this.list[key].push(callback);
};
//發佈消息的功能
PubSub.prototype.publish = function(key, args) {
var fns = this.list[key];
// 若是沒有訂閱過該消息的話,則返回
if (!fns || fns.length === 0) {
return;
}
var len = fns.length;
while (len--) {
fns[len].apply(this, args);
}
};
// 取消訂閱
PubSub.prototype.unsubscribe = function(key, fn) {
var fns = this.list[key];
if (!fns || fns.length === 0) {
return false;
}
if (!fn) {
fns && (fns.length = 0);
} else {
// 將fn刪除
var len = fns.length;
while (len--) {
if (fns[len] === fn) {
fns.splice(len, 1);
}
}
}
};
 
下面利用發佈/訂閱模式實現異步編程
var pubsub = new PubSub();
pubsub.subscribe("msg", cbFun);
function cbFun() {
console.log("hello word!");
}
function asyncFun() {
setTimeout(() => {
pubsub.publish("msg");
}, 3000);
}
asyncFun(); 
這種方法的性質與"事件監聽"相似,可是明顯優於後者。由於咱們能夠經過查看"消息中心",瞭解存在多少信號、每一個信號有多少訂閱者,從而監控程序的運行。
 
4.Promise
Promise 是一個對象,從它能夠獲取異步操做的消息。Promise 提供統一的 API,各類異步操做均可以用一樣的方法進行處理。
Promise對象有如下兩個特色。
(1)對象的狀態不受外界影響。Promise對象表明一個異步操做,有三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗)。只有異步操做的結果,能夠決定當前是哪種狀態,任何其餘操做都沒法改變這個狀態。這也是Promise這個名字的由來,它的英語意思就是「承諾」,表示其餘手段沒法改變。
(2)一旦狀態改變,就不會再變,任什麼時候候均可以獲得這個結果。Promise對象的狀態改變,只有兩種可能:從pending變爲fulfilled和從pending變爲rejected。只要這兩種狀況發生,狀態就凝固了,不會再變了,會一直保持這個結果,這時就稱爲 resolved(已定型)。若是改變已經發生了,你再對Promise對象添加回調函數,也會當即獲得這個結果。這與事件(Event)徹底不一樣,事件的特色是,若是你錯過了它,再去監聽,是得不到結果的。
function cbFun() {
console.log("hello word!");
}
function asyncFun(callback) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 3000);
});
}
asyncFun().then(()=>{
cbFun()
}) 
Promise也有一些缺點。首先,沒法取消Promise,一旦新建它就會當即執行,沒法中途取消。其次,若是不設置回調函數,Promise內部拋出的錯誤,不會反應到外部。第三,當處於pending狀態時,沒法得知目前進展到哪個階段(剛剛開始仍是即將完成)
 
5.async/await
目前async/await方法被做爲前端異步的終極方案,由於其在語義化方面很是友好,對於代碼的維護很是簡單,只須要返回promise並await 它就好。
function cbFun() {
console.log("hello word!");
}
function asyncFun() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 3000);
});
}
async function asyncFunArr() {
await asyncFun();
cbFun();
}
asyncFunArr();

  參考:javascript

Javascript異步編程的4種方法

相關文章
相關標籤/搜索