JavaScript的異步編程

越來越發(fā)現(xiàn)JavaScript這個語言相當?shù)牟诲e,之前還一直以為就跟HTML,CSS一樣差不多(實際上這兩者的門道也不淺)玄组。隨著AJAX滔驾,ES6,甚至ES7新標準新特性俄讹,很多玩法加入進來哆致,再加上node的推動下JavaScript的生態(tài)也越來越好,多學習一下人很有裨益患膛。

(題外插一句摊阀,這個簡書貌似沒有支持MarkDown,光靠編輯器這幾個功能可能支持得不夠踪蹬,還有就是代碼段也沒有嗎胞此。)


1 最原始的異步編程

其實就是搞一個嵌套一類的東西,非常的oldschool跃捣,用setTimeOut來舉例子(工作中可以將其替換成ajax網(wǎng)絡(luò)請求漱牵,獲取到結(jié)果執(zhí)行下一步的)

比如弄一個簡單的例子,一方面來證明是異步的疚漆,復制到瀏覽器的conclose里即可酣胀。

```javascript

function a (){

console.log("我是a我不是異步代碼")

setTimeout(

function(){console.log("我是a的異步代碼")}

,1000)

}

function b (){

console.log("我是b我不是異步代碼")

setTimeout(

function(){console.log("我是b的異步代碼")}

,1000)

}

a()

b()

```

看到a異步代碼永遠是在b的非異步代碼后面執(zhí)行,無論你怎么設(shè)置延時的定時器時間哪怕是設(shè)置為0娶聘,而且b的異步代碼也不會跑在b的前面闻镶。同樣作為異步代碼他會在滿足條件時才會觸發(fā),但是問題來了我要是好幾層怎么辦丸升,A依賴于B的請求返回結(jié)果铆农,B依賴于C的請求返回結(jié)果。发钝。顿涣。。酝豪,很可能是下面的情況

```javascript

setTimeout(

? () => {

? ? console.log("ZP很帥 +"+ 1);

? ? setTimeout(

? ? ? () => {

? ? ? ? console.log("ZP很帥 +" +2);

? ? ? ? setTimeout(

? ? ? ? ? () => {

? ? ? ? ? ? console.log("ZP很帥 +"+ 3);

? ? ? ? ? },

? ? ? ? ? 1000

? ? ? ? );

? ? ? },

? ? ? 1000

? ? );

? },

? 1000

)

```

但是這個東西看起來就知道不夠優(yōu)雅涛碑,怎么樣寫得更簡潔呢,可以試著分離一下孵淘。我在別的大佬的JS里經(jīng)常會遇到各種XXXXCallBack蒲障,借鑒一下人家的分離思想揉阎。

```javascript

var run = (steps, callback) => {

? setTimeout(

? ? () => {

? ? ? console.log("張鵬真的很帥 +" +steps);

? ? ? callback();

? ? },

? ? 1000

? );

};

run(1, () => {

? run(2, () => {

? ? run(3, () => {});

? });

});

```

其實已經(jīng)很不錯了,因為在JS里面函數(shù)也可以作為參數(shù)傳參進來這個特性烙如,剛開始這個我這個彎沒轉(zhuǎn)過來浪費了不少時間。

2 ES6新特性 promise

其實做到分離徘溢,還是會出現(xiàn)嵌套的問題對于這種嵌套的代碼還有個稱呼,“厄運金字塔”(其實挺貼切的想要得到你的結(jié)果從塔頂?shù)剿馐┟郏@種代碼改起來最蛋疼七扭八歪的翻默。)

于是ES6提供了個原生支持叫做promise來解決,他的構(gòu)造方法接受一個函數(shù),并且這個函數(shù)接受resolve和reject這兩個參數(shù)蹦渣。前者未來成功時調(diào)用后者未來失敗時調(diào)用(其實第一個厄運金字塔代碼類型callBack也可以分為成功的successCallBack和失敗的failCallBack于是代碼更難改。)

```javascript

var run = steps =>

? () =>

? ? new Promise((resolve, reject) => {

? ? ? setTimeout(

? ? ? ? () => {

? ? ? ? ? console.log(steps);

? ? ? ? ? resolve(); // 一秒后的未來執(zhí)行成功,需要調(diào)用

? ? ? ? },

? ? ? ? 1000

? ? ? );

? ? });

Promise.resolve()

? .then(run(1))

? .then(run(2))

? .then(run(3));

```

當然前半段代碼看不明白也沒關(guān)系,箭頭函數(shù) =>這個讓代碼變簡潔是個不錯的東西,當然也提高了閱讀的門檻袱箱,下面是我從MDN上找到

```javascript

(參數(shù)1, 參數(shù)2, …, 參數(shù)N) => { 函數(shù)聲明 }

//相當于:(參數(shù)1, 參數(shù)2, …, 參數(shù)N) =>{ return 表達式; }

(參數(shù)1, 參數(shù)2, …, 參數(shù)N) => 表達式(單一)

// 當只有一個參數(shù)時凉翻,圓括號是可選的:

(單一參數(shù)) => {函數(shù)聲明}

單一參數(shù) => {函數(shù)聲明}

// 沒有參數(shù)的函數(shù)應該寫成一對圓括號前计。

() => {函數(shù)聲明}

```

我的改寫可能讓你大概了解一點,異步函數(shù)有好處也有壞處伶棒,但是它確實能讓代碼簡短骇钦。

```javascript

var run = function run (steps){

new Primise(function(resolve,reject){

setTimeout({

console.log(steps);

resolve(function(steps));

},1000)

})

}?

Promise.resolve()

? .then(run(1))

? .then(run(2))

? .then(run(3));

```

是不是就沒有嵌套了,最起碼第一眼看上去很像同步代碼寇蚊,直觀的鏈式調(diào)用。

3 ES7的await和async語法糖

async標記函數(shù)為異步函數(shù),await表示他后面要返回為一個Promise對象,在這個promise的異步結(jié)果出來之后就再繼續(xù)往下執(zhí)行掂墓。

```javascript

var run = async steps => {

? await wait(1000);

? console.log(steps);

}

```

4 用生成器實現(xiàn)協(xié)程

協(xié)程是在線程里面川慌,所以是共享的線程資源,甚至連線程間切換消耗資源都省了。協(xié)程 Coroutine,一種協(xié)作多任務(wù)式多任務(wù)的亮靴,任務(wù)掛起與恢復實現(xiàn)任務(wù)間切換。

知道go的人肯定對協(xié)程有聽過(然而我目前也只是聽過于置,看過資料了解過的程度茧吊。)JavaScript是怎么實現(xiàn)協(xié)程,并沒有什么關(guān)鍵詞八毯。于是要通過生成器Generator來實現(xiàn)這個玩意搓侄,在JavaScript的“可迭代協(xié)議”和“迭代器協(xié)議”,function*和yield關(guān)鍵字配合下就完成了话速。

function*是生成生成器對象的讶踪,yield是用來在生成器的next()方法執(zhí)行時中斷位置返回右側(cè)表達式的值。

```javascript

function* IdGenerator() {

? let index = 1;

? while (true)

? ? yield index++;

}

var idGenerator = IdGenerator();

console.log(idGenerator.next());

console.log(idGenerator.next());

```

5 異步異常

其實異步代碼異常是一個問題泊交,現(xiàn)實中涉及到請求的尤其是這樣很可能是兩套邏輯再嵌套的那種乳讥。

原始的兩種callback,promise有resolve和reject兩種,await廓俭,async也有對應的將結(jié)果解析出來云石,生成器沒怎么細了解過,但是MDN上解釋還挺清楚的研乒。

熊四火老師的專欄關(guān)于這個異步寫的比較好建議多看幾遍汹忠。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子宽菜,更是在濱河造成了極大的恐慌谣膳,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铅乡,死亡現(xiàn)場離奇詭異继谚,居然都是意外死亡,警方通過查閱死者的電腦和手機隆判,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進店門犬庇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人侨嘀,你說我怎么就攤上這事∥娼螅” “怎么了咬腕?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長葬荷。 經(jīng)常有香客問我涨共,道長,這世上最難降的妖魔是什么宠漩? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任举反,我火速辦了婚禮,結(jié)果婚禮上扒吁,老公的妹妹穿的比我還像新娘火鼻。我一直安慰自己,他們只是感情好雕崩,可當我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布魁索。 她就那樣靜靜地躺著,像睡著了一般盼铁。 火紅的嫁衣襯著肌膚如雪粗蔚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天饶火,我揣著相機與錄音鹏控,去河邊找鬼。 笑死肤寝,一個胖子當著我的面吹牛当辐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播醒陆,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼瀑构,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起寺晌,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤世吨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后呻征,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體耘婚,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年陆赋,在試婚紗的時候發(fā)現(xiàn)自己被綠了沐祷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡攒岛,死狀恐怖赖临,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情灾锯,我是刑警寧澤兢榨,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站顺饮,受9級特大地震影響吵聪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜兼雄,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一吟逝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧赦肋,春花似錦块攒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至恕稠,卻和暖如春琅绅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鹅巍。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工千扶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人骆捧。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓澎羞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親敛苇。 傳聞我的和親對象是個殘疾皇子妆绞,可洞房花燭夜當晚...
    茶點故事閱讀 44,969評論 2 355

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

  • Promise 對象 Promise 的含義 Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函...
    neromous閱讀 8,706評論 1 56
  • 在單線程的javascript編程來說,所有的任務(wù)分為兩種,一種是同步任務(wù)(synchronous), 另一種是異...
    kallsaver閱讀 342評論 0 0
  • 弄懂js異步 講異步之前,我們必須掌握一個基礎(chǔ)知識-event-loop括饶。 我們知道JavaScript的一大特點...
    DCbryant閱讀 2,711評論 0 5
  • 摘要: 深度理解JS事件循環(huán)V瓴琛!图焰! 原文:JavaScript是如何工作的:事件循環(huán)和異步編程的崛起+ 5種使用 ...
    Fundebug閱讀 3,371評論 0 35
  • 同步和異步 同步編程启盛,就是計算機一行一行按照順序依次執(zhí)行代碼,當前代碼任務(wù)耗時執(zhí)行會阻塞后續(xù)代碼的執(zhí)行技羔。 同步編輯...
    vuturn閱讀 272評論 0 0