原文:阮一峯 JavaScript異步編程的4種方法javascript
1、回調函數html
這是異步編程最基本的方法java
假定有兩個函數f1和f2,後者等待前者的執行結果。ajax
f1();
f2();
若是f1是一個很耗時的任務,能夠考慮改寫f1,把f2寫成f1的回調函數編程
function f1(callback) { setTimeout(function(){ callback() }, 1000) } f1(f2);
採用這種方式,咱們把同步操做變成了異步操做,f1不會堵塞程序運行,至關於先執行程序的主要邏輯,將耗時的操做推遲執行。異步
回調函數的優勢是簡單、容易理解和部署async
缺點是不利於代碼的閱讀和維護,各個部分之間高度耦合,流程會很混亂,並且每一個任務只能指定一個回調函數。另外,回調地獄,不能用try catch捕獲錯誤,不能return模塊化
2、事件監聽異步編程
另外一種思路是採用事件驅動模式。任務的執行不取決於代碼的順序,而取決於某個事件是否發生。函數
f1.on('done', f2); function f1() { setTimeout(function() { f1.trigger('done'); }) }
f1.trgger('done')表示執行完成後,當即觸發done事件,從而開始執行f2
這種方法的優勢是比較容易理解,能夠綁定多個事件,每一個事件能夠指定多個回調函數,從而能夠去耦合,有利於實現模塊化。缺點是整個程序都要變成事件驅動型,運行流程會變得很不清晰。
3、發佈/訂閱(觀察者模式)
上一節的「事件」,能夠理解成「信號」。
咱們假定,存在一個「信號中心」,某個任務執行完成,就向信號中心「發佈」一個信號,其餘任務能夠向信號中心「訂閱」這個信號,從而知道何時本身能夠開始執行。
jQuery.subscribe("done", f2); //訂閱 function f1() { setTimeout(function () { jQuery.publish("done"); //發佈 }, 3000) } function f2 () { alert('hello'); } f1(); jQuery.unsubscribe("done", f2); // 取消訂閱
jQuery.publish("done")的意思是,f1執行完成後,向「信號中心」jQuery「發佈「done」信號,從而引起f2的執行
f2完成執行後,也能夠取消訂閱(unsubscribe)
這種方法的性質與「事件監聽」相似,可是明顯優於後者,由於咱們能夠經過查看「消息中心」,瞭解存在多少信號、每一個信號有多少訂閱者,從而監控程序的運行。
4、Promise對象
Promise對象是CommonJS工做組提出的一種規範,目的是爲異步編程提供統一的接口。
簡單說,它的思想是,每個異步任務返回一個Promise對象,該對象有一個then方法,容許指定回調函數。好比,f1的回調函數f2,能夠寫成:
f1().then(f2);
ajax('XXX1') .then(res => { // 操做邏輯 return ajax('XXX2') }).then(res => { // 操做邏輯 return ajax('XXX3') }).then(res => { // 操做邏輯 })
Promise的優勢是解決了回調地獄的問題。缺點是沒法取消Promise,錯誤須要經過回調函數來捕獲。