javascript異步變遷(一)

你可能知道介杆,javascript在瀏覽器端是一門單線程的語言(single thread)鹃操。道理很簡(jiǎn)單椰拒,就是設(shè)計(jì)者當(dāng)時(shí)設(shè)計(jì)這門語言的時(shí)候只是考慮到這門語言就是一個(gè)腳本語言,應(yīng)該足夠簡(jiǎn)單缆毁,要易于上手。

隊(duì)列

  但是慢慢的發(fā)展就會(huì)產(chǎn)生一個(gè)問題,單線程一次只能執(zhí)行一個(gè)任務(wù),如果有多個(gè)任務(wù)同時(shí)執(zhí)行,就必須排隊(duì),前面一個(gè)任務(wù)完成才能執(zhí)行后面一個(gè)任務(wù),以此類推。
  這種模式下你不用考慮復(fù)雜的線程安全滨溉,也不用考慮線程通信得哆,故出發(fā)點(diǎn)是好的。但是有一個(gè)壞處,會(huì)發(fā)生線程阻塞,就是一個(gè)耗時(shí)很長(zhǎng)的任務(wù)如果沒有執(zhí)行完,就會(huì)阻塞之后任務(wù)的執(zhí)行。通俗的講就是會(huì)造成瀏覽器的假死
  為了解決這個(gè)問題,Javascript語言將任務(wù)的執(zhí)行模式分成兩種:同步(Synchronous)和異步(Asynchronous)作箍。

  • "同步模式"就是上一段的模式屹电,后一個(gè)任務(wù)等待前一個(gè)任務(wù)結(jié)束外莲,然后再執(zhí)行,程序的執(zhí)行順序與任務(wù)的排列順序是一致的、同步的;"異步模式"則完全不同,每一個(gè)任務(wù)有一個(gè)或多個(gè)回調(diào)函數(shù)(callback),前一個(gè)任務(wù)結(jié)束后,不是執(zhí)行后一個(gè)任務(wù),而是執(zhí)行回調(diào)函數(shù),后一個(gè)任務(wù)則是不等前一個(gè)任務(wù)結(jié)束就執(zhí)行,所以程序的執(zhí)行順序與任務(wù)的排列順序是不一致的、異步的吵冒。
  • "異步模式"非常重要。在瀏覽器端南捂,耗時(shí)很長(zhǎng)的操作都應(yīng)該異步執(zhí)行,避免瀏覽器失去響應(yīng),最好的例子就是Ajax操作。在服務(wù)器端,"異步模式"甚至是唯一的模式矗烛,因?yàn)閳?zhí)行環(huán)境是單線程的股冗,如果允許同步執(zhí)行所有http請(qǐng)求怯疤,服務(wù)器性能會(huì)急劇下降,很快就會(huì)失去響應(yīng)。
    本文總結(jié)了"異步模式"編程的4種方法湘纵,理解它們可以讓你寫出結(jié)構(gòu)更合理、性能更出色痰哨、維護(hù)更方便的Javascript程序撬讽。
異步

提示:異步不代表加快執(zhí)行,通常我們說的異步是異步I/O鸯绿,我們知道I/O操作遠(yuǎn)沒有CPU的處理速度快瓶蝴。當(dāng)我們?nèi)フ?qǐng)求一個(gè)HTTP服務(wù)男窟、查詢一段SQL歉眷,讀取一個(gè)文件的時(shí)候春缕,會(huì)出現(xiàn)CPU占用不完全的情況米间,這個(gè)時(shí)候CPU必須要等待I/O操作完成,這個(gè)等待時(shí)間是不定的稚配,就會(huì)導(dǎo)致CPU資源浪費(fèi)畅涂。
合理的解決辦法就是采用異步操作,當(dāng)處于I/O等待狀態(tài)就將CPU轉(zhuǎn)換到其它任務(wù)當(dāng)中道川,I/O結(jié)束等待后就重新獲得該方法的控制權(quán)繼續(xù)執(zhí)行午衰。


回調(diào)函數(shù)

JavaScript語言對(duì)異步編程的實(shí)現(xiàn)立宜,就是回調(diào)函數(shù)。所謂回調(diào)函數(shù)苇经,就是把任務(wù)的第二段單獨(dú)寫在一個(gè)函數(shù)里面赘理,等到重新執(zhí)行這個(gè)任務(wù)的時(shí)候,就直接調(diào)用這個(gè)函數(shù)扇单。它的英語名字callback商模,直譯過來就是"重新調(diào)用"。

先看一個(gè)最簡(jiǎn)單的回調(diào)

function f1(callback){
    //setTimeout是最簡(jiǎn)單的回調(diào)函數(shù)蜘澜,等待一段時(shí)間后執(zhí)行
  setTimeout(function () {
  // f1的任務(wù)代碼
  callback();
  }, 1000);
}

當(dāng)我們執(zhí)行f1這個(gè)函數(shù)的時(shí)候施流,我們會(huì)加載一個(gè)定時(shí)器方法,1秒過后鄙信,會(huì)執(zhí)行它的回調(diào)函數(shù)
讀取文件進(jìn)行處理瞪醋,是這樣寫的。

 fs.readFile('/etc/passwd', function (err, data) {
     if (err) throw err;
     console.log(data);
 });console.log(data);});

上面代碼讀取了一個(gè)文件装诡,回調(diào)函數(shù)有兩個(gè)參數(shù)银受,第一個(gè)為錯(cuò)誤對(duì)象,第二個(gè)為讀取到的數(shù)據(jù)
讓情況稍微復(fù)雜一點(diǎn)
看下面這個(gè)代碼

 $.post("/ajax/post1",function(data){
    if(data.type=="book"){
        $.post("/ajax/book",function(data1){
            console.log(data1);
        });
    }else if(data.type=="article"){
        $.post("/ajax/article",function(data2){
            console.log(data2);
        });
    }
});

這個(gè)例子先請(qǐng)求了一個(gè)服務(wù)鸦采,根據(jù)返回的結(jié)果宾巍,判斷它是哪一種狀態(tài),在根據(jù)它的狀態(tài)又請(qǐng)求了一次服務(wù)渔伯。這個(gè)例子看起來還比較好受顶霞,我們?cè)诳聪旅孢@種狀態(tài),是不是大家都很熟悉锣吼。

                    });
                  });
                });
              });
            });
          });
        });
      });
    });
  });
});

上面這段代碼就是javascript著名的回調(diào)陷阱选浑,多次的嵌套回調(diào)會(huì)讓你的代碼亂成一團(tuán),并且難以維護(hù)
所以機(jī)智的開發(fā)人員為了解決這個(gè)問題玄叠,他們采取了很多種辦法古徒,咱們從簡(jiǎn)單的開始分析

異步函數(shù)式類庫

  • Async.js
  • When.js
  • parallel.js
  • ...

上面這些庫有一個(gè)共同點(diǎn),就是通過函數(shù)的方式把異步方法嵌套在了一起诸典,其實(shí)異步的本質(zhì)還是沒有改變描函,他們都基于Promises/A規(guī)范
而且這些庫還有一個(gè)共通點(diǎn)狐粱,支持同步方法的隊(duì)列執(zhí)行舀寓,這個(gè)在js動(dòng)畫、集合處理等用的比較多肌蜻,這里不多闡述互墓。
我們這里拿When.js來講解,首先蒋搜,我們看一段代碼:

var getData = function(callback) {
    $.getJSON(api, function(data){
        callback(data[0]);
    });
}
var getImg = function(src, callback) {
    var img = new Image();
    img.onload = function() {
        callback(img);
    };
    img.src = src;
}
var showImg = function(img) {
    $(img).appendTo($('#container'));
}
getData(function(data) {
    getImg(data, function(img) {
        showImg(img);
    });
});

這段代碼完成了三個(gè)任務(wù):1)獲取數(shù)據(jù)篡撵;2)加載圖片判莉;3)顯示圖片,其中育谬,任務(wù)1和2是異步券盅,3是同步,使用的是最常見的callback機(jī)制來處理異步邏輯膛檀,好處是淺顯易懂锰镀,缺點(diǎn)是強(qiáng)耦合、不直觀咖刃、處理異常麻煩等等泳炉。
另外一種常見的實(shí)現(xiàn)異步編程的方案是事件監(jiān)聽器,例如使用QWrap的CustEvent嚎杨,讓任務(wù)成功時(shí)fireEvent花鹅,那么注冊(cè)了這個(gè)Event的監(jiān)聽器就可以收到這個(gè)事件,并收到事件傳遞過來的數(shù)據(jù)枫浙,Dom標(biāo)準(zhǔn)事件也是采用的這種形式刨肃。這種方案也很好理解,代碼從略箩帚。事件監(jiān)聽可以解耦之景,可以綁定任意多個(gè)監(jiān)聽器,但是依然不直觀膏潮,而且事件發(fā)生之后再綁定的監(jiān)聽器也得不到觸發(fā)。

我們嘗試用when.js改寫下這段代碼

var getData = function () {
      var deferred = when.defer();

      $.getJSON(api, function (data) {
          deferred.resolve(data[0]);
      });

      return deferred.promise;
}
var getImg = function (src) {
      var deferred = when.defer();
      var img = new Image();
      img.onload = function () {
          deferred.resolve(img);
      };
      img.src = src;
      return deferred.promise;
}
var showImg = function (img) {
      $(img).appendTo($('#container'));
}
getData()
      .then(getImg)
      .then(showImg);

看最后三行代碼满力,是不是一目了然焕参,非常的語義化?
他解決了一個(gè)問題油额,就是我們前面提到的嵌套陷阱叠纷!
OK!下一章讓我們來看一下Whenjs還有什么功能潦嘶,當(dāng)然這里的重點(diǎn)不是這個(gè)庫涩嚣,大家感興趣的話可以自己去看看when.js,我們的重點(diǎn)是Promises/A規(guī)范

下一章我們繼續(xù)

Promises/A規(guī)范詳細(xì)闡述說明

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末掂僵,一起剝皮案震驚了整個(gè)濱河市航厚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌锰蓬,老刑警劉巖幔睬,帶你破解...
    沈念sama閱讀 216,744評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異芹扭,居然都是意外死亡麻顶,警方通過查閱死者的電腦和手機(jī)赦抖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辅肾,“玉大人队萤,你說我怎么就攤上這事〗玫觯” “怎么了要尔?”我有些...
    開封第一講書人閱讀 163,105評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)份汗。 經(jīng)常有香客問我盈电,道長(zhǎng),這世上最難降的妖魔是什么杯活? 我笑而不...
    開封第一講書人閱讀 58,242評(píng)論 1 292
  • 正文 為了忘掉前任匆帚,我火速辦了婚禮,結(jié)果婚禮上旁钧,老公的妹妹穿的比我還像新娘吸重。我一直安慰自己,他們只是感情好歪今,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評(píng)論 6 389
  • 文/花漫 我一把揭開白布嚎幸。 她就那樣靜靜地躺著,像睡著了一般寄猩。 火紅的嫁衣襯著肌膚如雪嫉晶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,215評(píng)論 1 299
  • 那天田篇,我揣著相機(jī)與錄音替废,去河邊找鬼。 笑死泊柬,一個(gè)胖子當(dāng)著我的面吹牛椎镣,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播兽赁,決...
    沈念sama閱讀 40,096評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼状答,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了刀崖?” 一聲冷哼從身側(cè)響起惊科,我...
    開封第一講書人閱讀 38,939評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎亮钦,沒想到半個(gè)月后译断,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,354評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡或悲,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評(píng)論 2 333
  • 正文 我和宋清朗相戀三年孙咪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了堪唐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,745評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡翎蹈,死狀恐怖淮菠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情荤堪,我是刑警寧澤合陵,帶...
    沈念sama閱讀 35,448評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站澄阳,受9級(jí)特大地震影響拥知,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜碎赢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評(píng)論 3 327
  • 文/蒙蒙 一低剔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧肮塞,春花似錦襟齿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至拷窜,卻和暖如春开皿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背篮昧。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評(píng)論 1 269
  • 我被黑心中介騙來泰國打工副瀑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人恋谭。 一個(gè)月前我還...
    沈念sama閱讀 47,776評(píng)論 2 369
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像挽鞠,于是被迫代替她去往敵國和親疚颊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,082評(píng)論 25 707
  • 異步編程對(duì)JavaScript語言太重要信认。Javascript語言的執(zhí)行環(huán)境是“單線程”的材义,如果沒有異步編程,根本...
    呼呼哥閱讀 7,311評(píng)論 5 22
  • 歡迎閱讀專門探索 JavaScript 及其構(gòu)建組件的系列文章的第四章嫁赏。 在識(shí)別和描述核心元素的過程中其掂,我們還分享...
    OSC開源社區(qū)閱讀 1,152評(píng)論 1 10
  • 2017年5月19日 星期五 天氣晴 崔笑媽媽親子日記 用心做一件事才有可能能把一件事情做的很好!但是...
    崔笑媽媽閱讀 239評(píng)論 1 2
  • 活在他的世界里潦蝇,我沒了自我款熬,眼里只有他深寥,擔(dān)心某一天,他有外遇贤牛,社會(huì)的誘惑那么大惋鹅,他外遇了,我怎么辦殉簸?我總是這樣...
    Cuilyling閱讀 178評(píng)論 0 0