Javascript中的async await

async / await是ES7的重要特性之一娘赴,也是目前社區(qū)里公認(rèn)的優(yōu)秀異步解決方案扔傅。目前,async / await這個(gè)特性已經(jīng)是stage 3的建議诡蜓,可以看看TC39的進(jìn)度熬甫,本篇文章將分享async / await是如何工作的,閱讀本文前蔓罚,希望你具備Promise椿肩、generator、yield等ES6的相關(guān)知識(shí)豺谈。

在詳細(xì)介紹async / await之前郑象,先回顧下目前在ES6中比較好的異步處理辦法。下面的例子中數(shù)據(jù)請(qǐng)求用Node.js中的request模塊茬末,數(shù)據(jù)接口采用Github v3 api文檔提供的repo代碼倉(cāng)庫(kù)詳情API作為例子演示厂榛。

Promise對(duì)異步的處理

雖然Node.js的異步IO帶來(lái)了對(duì)高并發(fā)的良好支持盖矫,同時(shí)也讓“回調(diào)”成為災(zāi)難,很容易造成回調(diào)地獄击奶。傳統(tǒng)的方式比如使用具名函數(shù)辈双,雖然可以減少嵌套的層數(shù),讓代碼看起來(lái)比較清晰柜砾。但是會(huì)造成比較差的編碼和調(diào)試體驗(yàn)湃望,你需要經(jīng)常使用用ctrl + f去尋找某個(gè)具名函數(shù)的定義,這使得IDE窗口經(jīng)常上下來(lái)回跳動(dòng)痰驱。使用Promise之后证芭,可以很好的減少嵌套的層數(shù)。另外Promise的實(shí)現(xiàn)采用了狀態(tài)機(jī)萄唇,在函數(shù)里面可以很好的通過(guò)resolve和reject進(jìn)行流程控制檩帐,你可以按照順序鏈?zhǔn)降娜?zhí)行一系列代碼邏輯了。下面是使用Promise的一個(gè)例子:

const request = require('request');
// 請(qǐng)求的url和header
const options = {
  url: 'https://api.github.com/repos/cpselvis/zhihu-crawler',
  headers: {
    'User-Agent': 'request'
  }
};
// 獲取倉(cāng)庫(kù)信息
const getRepoData = () => {
  return new Promise((resolve, reject) => {
    request(options, (err, res, body) => {
      if (err) {
        reject(err);
      }
      resolve(body);
    });
  });
};

getRepoData()
  .then((result) => console.log(result);)
  .catch((reason) => console.error(reason););

// 此處如果是多個(gè)Promise順序執(zhí)行的話另萤,如下:
// 每個(gè)then里面去執(zhí)行下一個(gè)promise
// getRepoData()
//   .then((value2) => {return promise2})
//   .then((value3) => {return promise3})
//   .then((x) => console.log(x))

不過(guò)Promise仍然存在缺陷湃密,它只是減少了嵌套,并不能完全消除嵌套四敞。舉個(gè)例子泛源,對(duì)于多個(gè)promise串行執(zhí)行的情況,第一個(gè)promise的邏輯執(zhí)行完之后忿危,我們需要在它的then函數(shù)里面去執(zhí)行第二個(gè)promise达箍,這個(gè)時(shí)候會(huì)產(chǎn)生一層嵌套。另外铺厨,采用Promise的代碼看起來(lái)依然是異步的缎玫,如果寫(xiě)的代碼如果能夠變成同步該多好啊解滓!

Generator對(duì)異步的處理

談到generator赃磨,你應(yīng)該不會(huì)對(duì)它感到陌生。在Node.js中對(duì)于回調(diào)的處理洼裤,我們經(jīng)常用的TJ / Co就是使用generator結(jié)合promise來(lái)實(shí)現(xiàn)的邻辉,co是coroutine的簡(jiǎn)稱,借鑒于python腮鞍、lua等語(yǔ)言中的協(xié)程值骇。它可以將異步的代碼邏輯寫(xiě)成同步的方式,這使得代碼的閱讀和組織變得更加清晰移国,也便于調(diào)試吱瘩。

const co = require('co');
const request = require('request');

const options = {
  url: 'https://api.github.com/repos/cpselvis/zhihu-crawler',
  headers: {
    'User-Agent': 'request'
  }
};
// yield后面是一個(gè)生成器 generator
const getRepoData = function* () {
  return new Promise((resolve, reject) => {
    request(options, (err, res, body) => {
      if (err) {
        reject(err);
      }
      resolve(body);
    });
  });
};

co(function* () {
  const result = yield getRepoData;
  // ... 如果有多個(gè)異步流程,可以放在這里迹缀,比如
  // const r1 = yield getR1;
  // const r2 = yield getR2;
  // const r3 = yield getR3;
  // 每個(gè)yield相當(dāng)于暫停使碾,執(zhí)行yield之后會(huì)等待它后面的generator返回值之后再執(zhí)行后面其它的yield邏輯皱卓。
  return result;
}).then(function (value) {
  console.log(value);
}, function (err) {
  console.error(err.stack);
});

async / await對(duì)異步的處理

雖然co是社區(qū)里面的優(yōu)秀異步解決方案,但是并不是語(yǔ)言標(biāo)準(zhǔn)部逮,只是一個(gè)過(guò)渡方案。ES7語(yǔ)言層面提供async / await去解決語(yǔ)言層面的難題嫂易。目前async / await 在 IE edge中已經(jīng)可以直接使用了兄朋,但是chrome和Node.js還沒(méi)有支持。幸運(yùn)的是怜械,babel已經(jīng)支持async的transform了颅和,所以我們使用的時(shí)候引入babel就行。在開(kāi)始之前我們需要引入以下的package缕允,preset-stage-3里就有我們需要的async/await的編譯文件峡扩。

無(wú)論是在Browser還是Node.js端都需要安裝下面的包。

$ npm install babel-core --save
$ npm install babel-preset-es2015 --save
$ npm install babel-preset-stage-3 --save

這里推薦使用babel官方提供的require hook方法障本。就是通過(guò)require進(jìn)來(lái)后教届,接下來(lái)的文件進(jìn)行require的時(shí)候都會(huì)經(jīng)過(guò)Babel的處理。因?yàn)槲覀冎繡ommonJs是同步的模塊依賴驾霜,所以也是可行的方法案训。這個(gè)時(shí)候,需要編寫(xiě)兩個(gè)文件粪糙,一個(gè)是啟動(dòng)的js文件强霎,另外一個(gè)是真正執(zhí)行程序的js文件。

啟動(dòng)文件index.js

require('babel-core/register');
require('./async.js');

真正執(zhí)行程序的async.js

const request = require('request');

const options = {
  url: 'https://api.github.com/repos/cpselvis/zhihu-crawler',
  headers: {
    'User-Agent': 'request'
  }
};

const getRepoData = () => {
  return new Promise((resolve, reject) => {
    request(options, (err, res, body) => {
      if (err) {
        reject(err);
      }
      resolve(body);
    });
  });
};

async function asyncFun() {
 try {
    const value = await getRepoData();
    // ... 和上面的yield類似蓉冈,如果有多個(gè)異步流程城舞,可以放在這里,比如
    // const r1 = await getR1();
    // const r2 = await getR2();
    // const r3 = await getR3();
    // 每個(gè)await相當(dāng)于暫停寞酿,執(zhí)行await之后會(huì)等待它后面的函數(shù)(不是generator)返回值之后再執(zhí)行后面其它的await邏輯家夺。
    return value;
  } catch (err) {
    console.log(err);
  }
}

asyncFun().then(x => console.log(`x: ${x}`)).catch(err => console.error(err));

注意點(diǎn):

async用來(lái)申明里面包裹的內(nèi)容可以進(jìn)行同步的方式執(zhí)行,await則是進(jìn)行執(zhí)行順序控制熟嫩,每次執(zhí)行一個(gè)await秦踪,程序都會(huì)暫停等待await返回值,然后再執(zhí)行之后的await掸茅。
await后面調(diào)用的函數(shù)需要返回一個(gè)promise椅邓,另外這個(gè)函數(shù)是一個(gè)普通的函數(shù)即可,而不是generator昧狮。
await只能用在async函數(shù)之中景馁,用在普通函數(shù)中會(huì)報(bào)錯(cuò)。
await命令后面的 Promise 對(duì)象逗鸣,運(yùn)行結(jié)果可能是 rejected合住,所以最好把 await 命令放在 try...catch 代碼塊中绰精。
其實(shí),async / await的用法和co差不多透葛,await和yield都是表示暫停笨使,外面包裹一層async 或者 co來(lái)表示里面的代碼可以采用同步的方式進(jìn)行處理。不過(guò)async / await里面的await后面跟著的函數(shù)不需要額外處理僚害,co是需要將它寫(xiě)成一個(gè)generator的硫椰。

青團(tuán)社招聘:

招聘崗位:資深前端開(kāi)發(fā)工程師

簡(jiǎn)歷投遞到:hr@qtshe.com || haochen@qtshe.com

職位描述:

1、建設(shè)工具萨蚕、提煉組件靶草、抽象框架,促進(jìn)前端工程化岳遥、服務(wù)化奕翔,持續(xù)提升研發(fā)效率,保障線上產(chǎn)品質(zhì)量

2浩蓉、構(gòu)建H5/PC應(yīng)用基礎(chǔ)設(shè)施派继,主導(dǎo)建設(shè)前端各種發(fā)布/監(jiān)控等平臺(tái),指導(dǎo)落實(shí)解決方案

3妻往、持續(xù)優(yōu)化前端頁(yè)面性能互艾,維護(hù)前端代碼規(guī)范,鉆研各種前沿技術(shù)和創(chuàng)新交互讯泣,增強(qiáng)用戶體驗(yàn)纫普、開(kāi)拓前端能力邊界

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市好渠,隨后出現(xiàn)的幾起案子昨稼,更是在濱河造成了極大的恐慌,老刑警劉巖拳锚,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件假栓,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡霍掺,警方通過(guò)查閱死者的電腦和手機(jī)匾荆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)杆烁,“玉大人牙丽,你說(shuō)我怎么就攤上這事⊥没辏” “怎么了烤芦?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)析校。 經(jīng)常有香客問(wèn)我构罗,道長(zhǎng)铜涉,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任遂唧,我火速辦了婚禮芙代,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘盖彭。我一直安慰自己链蕊,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布谬泌。 她就那樣靜靜地躺著,像睡著了一般逻谦。 火紅的嫁衣襯著肌膚如雪掌实。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,604評(píng)論 1 305
  • 那天邦马,我揣著相機(jī)與錄音贱鼻,去河邊找鬼。 笑死滋将,一個(gè)胖子當(dāng)著我的面吹牛邻悬,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播随闽,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼父丰,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了掘宪?” 一聲冷哼從身側(cè)響起蛾扇,我...
    開(kāi)封第一講書(shū)人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎魏滚,沒(méi)想到半個(gè)月后镀首,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鼠次,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年更哄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片腥寇。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡成翩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出花颗,到底是詐尸還是另有隱情捕传,我是刑警寧澤,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布扩劝,位于F島的核電站庸论,受9級(jí)特大地震影響职辅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜聂示,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一域携、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鱼喉,春花似錦秀鞭、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至编曼,卻和暖如春豆巨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背掐场。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工往扔, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人熊户。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓萍膛,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親嚷堡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蝗罗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

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

  • 異步編程對(duì)JavaScript語(yǔ)言太重要。Javascript語(yǔ)言的執(zhí)行環(huán)境是“單線程”的蝌戒,如果沒(méi)有異步編程绿饵,根本...
    呼呼哥閱讀 7,311評(píng)論 5 22
  • 弄懂js異步 講異步之前,我們必須掌握一個(gè)基礎(chǔ)知識(shí)-event-loop瓶颠。 我們知道JavaScript的一大特點(diǎn)...
    DCbryant閱讀 2,711評(píng)論 0 5
  • 本文首發(fā)在個(gè)人博客:http://muyunyun.cn/posts/7b9fdc87/ 提到 Node.js, ...
    牧云云閱讀 1,685評(píng)論 0 3
  • 本文的示例代碼參考這里的async 目錄 引言 callbackasync ?PromisePromise對(duì)象bl...
    諾之林閱讀 501評(píng)論 1 5
  • 今天學(xué)習(xí)了劉潤(rùn)老師的這節(jié)課讓我對(duì)于時(shí)間有了更透徹的理解拟赊,其實(shí)我是一個(gè)對(duì)于時(shí)間的概念還算清晰的人,在做任何事的...
    邊迪迪閱讀 281評(píng)論 0 2