Javascript異步回調

同步模式與異步模式

Javascript語言執行環境是“單線程”,一次執行一個任務,並且按照順序依次執行。
但是遇到耗時較長的任務會拖延整個程序的進度,造成瀏覽器無響應,頁面卡頓。
爲了解決這個問題,Javascript語言將任務的執行模式分爲兩種:

  • 異步模式 asynchronous
  • 同步模式 synchronous

同步模式就是,後一個任務等待前一個任務結束,然後再執行,程序的執行順序與任務的排列順序是一致的、同步的;
異步模式則完全不同,每一個任務有一個或多個回調函數(callback),前一個任務結束後,不是執行後一個任務,而是執行回調函數,後一個任務則是不等前一個任務結束就執行,所以程序的執行順序與任務的排列順序是不一致的、異步的。

在瀏覽器端,耗時很長的操作都應該異步執行,避免瀏覽器失去響應,最好的例子就是Ajax操作。在服務器端,"異步模式"甚至是唯一的模式,因爲執行環境是單線程的,如果允許同步執行所有http請求,服務器性能會急劇下降,很快就會失去響應。

這裏參考阮一峯老師的Javascript異步編程的4種方法

異步編程一:回調函數

這裏我看阮老師的文章不是很明白,參考:

JavaScript定時器及回調用法
簡析前端回調函數

回調函數就是一個參數,首先定義一個主函數,爲主函數設置一個入參;然後定義一個回調函數,將回調函數作爲參數傳入主函數。
執行時,主函數不必等到回調函數執行完畢可以繼續執行。所以回調函數一般用於耗時的操作。
優點:簡單、容易理解和部署。
缺點:不利於代碼閱讀和維護,各個部分之間高度耦合,流程很混亂,每個任務只能指定一個回調函數。

異步編程二:事件監聽

事件驅動模式。任務的執行不是取決於代碼的順序,而是取決於事件是否發生。
爲任務f1綁定一個事件:

f1.on('done', f2);

當f1發生事件“done"就觸發任務f2,執行f2。
然後,f1應寫爲:

function f1(){

    setTimeout(function () {

      // f1的任務代碼

      f1.trigger('done');

    }, 1000);

  }

f1.trigger(‘done’)表示,執行完成後,立即觸發done事件,從而開始執行f2。
優點:每個任務可以綁定多個事件,每個事件可以指定多個回調函數,可以去耦合,有利於實現模塊化
缺點:整個程序變成事件驅動型,運行流程會很不清晰。

異步編程三:發佈/訂閱

假設存在一個信號中心,當某個任務執行完成,向信號中心發佈publish一個信號,其他任務可以向信號中心訂閱subsrcibe這個信號,因此知道自己什麼時候可以執行。
這就是發佈-訂閱 模式publish-subsribe pattern觀察者模式observer pattern
首先,任務f2向信息中心訂閱happy信號

jQuery.subscribe("happy", f2);

f1進行如下改寫:

function f1(){
   setTimeout(function () {
     // f1的任務代碼
     jQuery.publish("happy");
   }, 1000);
 }

任務f1執行結束後,向信息中心發佈happy信號,任務f2在信息中心看到這樣的信號則開始執行。
任務f2完成執行後也可以取消訂閱信息:

jQuery.unsubscribe("happy", f2);

優點:每個任務可以發佈多個信號,每個信號可以被多個任務訂閱,可以去耦合,有利於實現模塊化;更好的是,我們可以通過信息中心知道存在多少信號,每個信號有多少訂閱者,從而監控程序的運行。
缺點:當訂閱者達到一定數量時,消息中心承受的壓力將會較大,全局消息充斥整個程序將會帶來不小的問題。

異步編程四:Promises對象

Promises對象爲異步編程提供統一的編程接口。
每一個異步任務都會返回一個Promises對象,這些對象都有一個then方法,可以指定回調函數,比如假如f1的回調函數是f2,就可以寫成:

f1().then(f2)

f1要進行如下改寫:

  function f1(){

    var dfd = $.Deferred();

    setTimeout(function () {

      // f1的任務代碼

      dfd.resolve();

    }, 500);

    return dfd.promise;

  }

也可以指定多個回調函數,以鏈式寫法完成:

f1().then(f2).then(f3);

再比如指定發生錯誤時的回調函數:

f1().then(f2).fail(f3);

優點:回調函數變成了鏈式寫法,程序的流程將會變得很清楚,而且有一整套配套的方法,可以實現許多強大的功能。

JQuery.promise()

而且,如果一個任務已經完成,再添加回調函數,該回調函數會立即執行。
缺點:難於理解和編寫。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章