JavaScript異步的實現

關鍵詞:異步

Javascript語言的執(zhí)行環(huán)境是"單線程"(single thread)

所謂"單線程",就是指一次只能完成一件任務。如果有多個任務貌嫡,就必須排隊,前面一個任務完成该溯,再執(zhí)行后面一個任務岛抄,以此類推,jQuery中隊列就是根據這個特性實現的狈茉。
看下這種模式的優(yōu)缺點:

  • 優(yōu)點:實現起來比較簡單夫椭,執(zhí)行環(huán)境相對單純;
  • 缺點:若一個任務耗時很長氯庆,會拖延整個程序的執(zhí)行蹭秋。常見的瀏覽器無響應(假死)

為了解決這個問題,Javascript語言將任務的執(zhí)行模式分成兩種:
同步(Synchronous)異步(Asynchronous)堤撵。

  • "同步模式"就是上一段的模式仁讨,后一個任務等待前一個任務結束,然后再執(zhí)行实昨,程序的執(zhí)行順序與任務的排列順序是一致的洞豁、同步的;

  • "異步模式"則完全不同荒给,每一個任務有一個或多個回調函數(callback)丈挟,前一個任務結束后,不是執(zhí)行后一個任務志电,而是執(zhí)行回調函數曙咽,后一個任務則是不等前一個任務結束就執(zhí)行,所以程序的執(zhí)行順序與任務的排列順序是不一致的溪北、異步的桐绒。

下面是"異步模式"的4種方法夺脾,理解它們可以讓你寫出結構更合理之拨、性能更出色茉继、維護更方便的Javascript程序。


一蚀乔、回調函數

這是異步編程最基本的方法烁竭。
假定有兩個函數f1和f2,后者等待前者的執(zhí)行結果吉挣。

  f1();
  f2();

如果f1是一個很耗時的任務派撕,可以考慮改寫f1,把f2寫成f1的回調函數睬魂。

  function f1(callback){
    setTimeout(function () {
      // f1的任務代碼
      callback();
    }, 1000);
  }

執(zhí)行代碼就變成下面這樣:
* f1(f2);

采用這種方式终吼,我們把同步操作變成了異步操作,f1不會堵塞程序運行氯哮,相當于先執(zhí)行程序的主要邏輯际跪,將耗時的操作推遲執(zhí)行。
回調函數的優(yōu)點是簡單喉钢、容易理解和部署姆打,缺點是不利于代碼的閱讀和維護,各個部分之間高度耦合肠虽,流程會很混亂幔戏,而且每個任務只能指定一個回調函數。

二税课、事件監(jiān)聽

另一種思路是采用事件驅動模式闲延。任務的執(zhí)行不取決于代碼的順序,而取決于某個事件是否發(fā)生韩玩。

還是以f1和f2為例慨代。首先,為f1綁定一個事件(這里采用的jQuery的寫法)啸如。

  f1.on('done', f2);

上面這行代碼的意思是侍匙,當f1發(fā)生done事件,就執(zhí)行f2叮雳。然后想暗,對f1進行改寫:

  function f1(){
    setTimeout(function () {
      // f1的任務代碼
      **f1.trigger('done');**
    }, 1000);
  }

f1.trigger('done')表示,執(zhí)行完成后帘不,立即觸發(fā)done事件说莫,從而開始執(zhí)行f2。

這種方法的優(yōu)點是比較容易理解寞焙,可以綁定多個事件储狭,每個事件可以指定多個回調函數互婿,而且可以"去耦合",有利于實現模塊化缺點是整個程序都要變成事件驅動型辽狈,運行流程會變得很不清晰慈参。

三、發(fā)布/訂閱

上一節(jié)的"事件"刮萌,完全可以理解成"信號"驮配。

我們假定,存在一個"信號中心"着茸,某個任務執(zhí)行完成壮锻,就向信號中心"發(fā)布"(publish)一個信號,其他任務可以向信號中心"訂閱"(subscribe)這個信號涮阔,從而知道什么時候自己可以開始執(zhí)行猜绣。這就叫做"發(fā)布/訂閱模式"publish-subscribe pattern,又稱"觀察者模式"
這個模式有多種實現敬特,下面采用的是Ben Alman的Tiny Pub/Sub掰邢,這是jQuery的一個插件。
首先擅羞,f2向"信號中心"jQuery訂閱"done"信號尸变。
* jQuery.subscribe("done", f2);

然后,f1進行如下改寫:

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

jQuery.publish("done")的意思是减俏,f1執(zhí)行完成后召烂,向"信號中心"jQuery發(fā)布"done"信號,從而引發(fā)f2的執(zhí)行娃承。
此外奏夫,f2完成執(zhí)行后,也可以取消訂閱(unsubscribe)历筝。
* jQuery.unsubscribe("done", f2);

這種方法的性質與"事件監(jiān)聽"類似酗昼,但是明顯優(yōu)于后者。因為我們可以通過查看"消息中心"梳猪,了解存在多少信號麻削、每個信號有多少訂閱者,從而監(jiān)控程序的運行春弥。

四呛哟、Promises對象

Promises對象是CommonJS工作組提出的一種規(guī)范,目的是為異步編程提供統一接口

簡單說匿沛,它的思想是扫责,每一個異步任務返回一個Promise對象,該對象有一個then方法逃呼,允許指定回調函數鳖孤。比如者娱,f1的回調函數f2,可以寫成:
* f1().then(f2);

  function f1(){
    var dfd = $.Deferred();
    setTimeout(function () {
      // f1的任務代碼
      dfd.resolve();
    }, 500);
    **return dfd.promise;**
  }

這樣寫的優(yōu)點在于,回調函數變成了鏈式寫法苏揣,程序的流程可以看得很清楚黄鳍,而且有一整套的配套方法,可以實現許多強大的功能腿准。
比如际起,指定多個回調函數:
* f1().then(f2).then(f3);

再比如拾碌,指定發(fā)生錯誤時的回調函數:
* f1().then(f2).fail(f3);

而且吐葱,它還有一個前面三種方法都沒有的好處:如果一個任務已經完成,再添加回調函數校翔,該回調函數會立即執(zhí)行弟跑。所以,你不用擔心是否錯過了某個事件或信號防症。這種方法的缺點就是編寫和理解孟辑,都相對比較難。


[參考文獻][]
[參考文獻]:http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末蔫敲,一起剝皮案震驚了整個濱河市饲嗽,隨后出現的幾起案子,更是在濱河造成了極大的恐慌奈嘿,老刑警劉巖貌虾,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異裙犹,居然都是意外死亡尽狠,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門叶圃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來袄膏,“玉大人,你說我怎么就攤上這事掺冠〕凉荩” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵德崭,是天一觀的道長斥黑。 經常有香客問我,道長接癌,這世上最難降的妖魔是什么心赶? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮缺猛,結果婚禮上缨叫,老公的妹妹穿的比我還像新娘椭符。我一直安慰自己,他們只是感情好耻姥,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布销钝。 她就那樣靜靜地躺著,像睡著了一般琐簇。 火紅的嫁衣襯著肌膚如雪蒸健。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天婉商,我揣著相機與錄音似忧,去河邊找鬼。 笑死丈秩,一個胖子當著我的面吹牛盯捌,可吹牛的內容都是我干的。 我是一名探鬼主播蘑秽,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼饺著,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了肠牲?” 一聲冷哼從身側響起幼衰,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎缀雳,沒想到半個月后渡嚣,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡俏险,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年严拒,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片竖独。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡裤唠,死狀恐怖,靈堂內的尸體忽然破棺而出莹痢,到底是詐尸還是另有隱情种蘸,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布竞膳,位于F島的核電站航瞭,受9級特大地震影響,放射性物質發(fā)生泄漏坦辟。R本人自食惡果不足惜刊侯,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望锉走。 院中可真熱鬧滨彻,春花似錦藕届、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至辜羊,卻和暖如春踏兜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背八秃。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工碱妆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人喜德。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓山橄,卻偏偏與公主長得像垮媒,于是被迫代替她去往敵國和親舍悯。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內容