欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入理解js 中async 函數(shù)的含義和用法

 更新時(shí)間:2018年05月13日 10:41:39   作者:阮一峰  
async 函數(shù)就是隧道盡頭的亮光,很多人認(rèn)為它是異步操作的終極解決方案。接下來(lái)通過(guò)本文給大家分享js 中async 函數(shù)的含義和用法,感興趣的朋友跟隨腳本之家小編一起看看吧

一、終極解決

異步操作是 JavaScript 編程的麻煩事,麻煩到一直有人提出各種各樣的方案,試圖解決這個(gè)問(wèn)題。

從最早的回調(diào)函數(shù),到 Promise 對(duì)象,再到 Generator 函數(shù),每次都有所改進(jìn),但又讓人覺(jué)得不徹底。它們都有額外的復(fù)雜性,都需要理解抽象的底層運(yùn)行機(jī)制。

異步I/O不就是讀取一個(gè)文件嗎,干嘛要搞得這么復(fù)雜?異步編程的最高境界,就是根本不用關(guān)心它是不是異步。

async 函數(shù)就是隧道盡頭的亮光,很多人認(rèn)為它是異步操作的終極解決方案。

二、async 函數(shù)是什么?

一句話(huà),async 函數(shù)就是 Generator 函數(shù)的語(yǔ)法糖。

前文有一個(gè) Generator 函數(shù),依次讀取兩個(gè)文件。

var fs = require('fs');
var readFile = function (fileName){
 return new Promise(function (resolve, reject){
  fs.readFile(fileName, function(error, data){
   if (error) reject(error);
   resolve(data);
  });
 });
};
var gen = function* (){
 var f1 = yield readFile('/etc/fstab');
 var f2 = yield readFile('/etc/shells');
 console.log(f1.toString());
 console.log(f2.toString());
};

寫(xiě)成 async 函數(shù),就是下面這樣。

var asyncReadFile = async function (){
 var f1 = await readFile('/etc/fstab');
 var f2 = await readFile('/etc/shells');
 console.log(f1.toString());
 console.log(f2.toString());
};

一比較就會(huì)發(fā)現(xiàn),async 函數(shù)就是將 Generator 函數(shù)的星號(hào)(*)替換成 async,將 yield 替換成 await,僅此而已。

三、async 函數(shù)的優(yōu)點(diǎn)

async 函數(shù)對(duì) Generator 函數(shù)的改進(jìn),體現(xiàn)在以下三點(diǎn)。

(1)內(nèi)置執(zhí)行器。 Generator 函數(shù)的執(zhí)行必須靠執(zhí)行器,所以才有了 co 函數(shù)庫(kù),而 async 函數(shù)自帶執(zhí)行器。也就是說(shuō),async 函數(shù)的執(zhí)行,與普通函數(shù)一模一樣,只要一行。

var result = asyncReadFile();

(2)更好的語(yǔ)義。 async 和 await,比起星號(hào)和 yield,語(yǔ)義更清楚了。async 表示函數(shù)里有異步操作,await 表示緊跟在后面的表達(dá)式需要等待結(jié)果。

(3)更廣的適用性。 co 函數(shù)庫(kù)約定,yield 命令后面只能是 Thunk 函數(shù)或 Promise 對(duì)象,而 async 函數(shù)的 await 命令后面,可以跟 Promise 對(duì)象和原始類(lèi)型的值(數(shù)值、字符串和布爾值,但這時(shí)等同于同步操作)。

四、async 函數(shù)的實(shí)現(xiàn)

async 函數(shù)的實(shí)現(xiàn),就是將 Generator 函數(shù)和自動(dòng)執(zhí)行器,包裝在一個(gè)函數(shù)里。

async function fn(args){
 // ...
}
// 等同于
function fn(args){ 
 return spawn(function*() {
  // ...
 }); 
}

所有的 async 函數(shù)都可以寫(xiě)成上面的第二種形式,其中的 spawn 函數(shù)就是自動(dòng)執(zhí)行器。

下面給出 spawn 函數(shù)的實(shí)現(xiàn),基本就是前文自動(dòng)執(zhí)行器的翻版。

function spawn(genF) {
 return new Promise(function(resolve, reject) {
  var gen = genF();
  function step(nextF) {
   try {
    var next = nextF();
   } catch(e) {
    return reject(e); 
   }
   if(next.done) {
    return resolve(next.value);
   } 
   Promise.resolve(next.value).then(function(v) {
    step(function() { return gen.next(v); });   
   }, function(e) {
    step(function() { return gen.throw(e); });
   });
  }
  step(function() { return gen.next(undefined); });
 });
}

async 函數(shù)是非常新的語(yǔ)法功能,新到都不屬于 ES6,而是屬于 ES7。目前,它仍處于提案階段,但是轉(zhuǎn)碼器 Babel 和 regenerator 都已經(jīng)支持,轉(zhuǎn)碼后就能使用。

五、async 函數(shù)的用法

同 Generator 函數(shù)一樣,async 函數(shù)返回一個(gè) Promise 對(duì)象,可以使用 then 方法添加回調(diào)函數(shù)。當(dāng)函數(shù)執(zhí)行的時(shí)候,一旦遇到 await 就會(huì)先返回,等到觸發(fā)的異步操作完成,再接著執(zhí)行函數(shù)體內(nèi)后面的語(yǔ)句。

下面是一個(gè)例子。

async function getStockPriceByName(name) {
 var symbol = await getStockSymbol(name);
 var stockPrice = await getStockPrice(symbol);
 return stockPrice;
}
getStockPriceByName('goog').then(function (result){
 console.log(result);
});

上面代碼是一個(gè)獲取股票報(bào)價(jià)的函數(shù),函數(shù)前面的async關(guān)鍵字,表明該函數(shù)內(nèi)部有異步操作。調(diào)用該函數(shù)時(shí),會(huì)立即返回一個(gè)Promise對(duì)象。

下面的例子,指定多少毫秒后輸出一個(gè)值。

function timeout(ms) {
 return new Promise((resolve) => {
  setTimeout(resolve, ms);
 });
}
async function asyncPrint(value, ms) {
 await timeout(ms);
 console.log(value)
}
asyncPrint('hello world', 50);

上面代碼指定50毫秒以后,輸出"hello world"。

六、注意點(diǎn)

await 命令后面的 Promise 對(duì)象,運(yùn)行結(jié)果可能是 rejected,所以最好把 await 命令放在 try...catch 代碼塊中。

async function myFunction() {
 try {
  await somethingThatReturnsAPromise();
 } catch (err) {
  console.log(err);
 }
}
// 另一種寫(xiě)法
async function myFunction() {
 await somethingThatReturnsAPromise().catch(function (err){
  console.log(err);
 });
}

await 命令只能用在 async 函數(shù)之中,如果用在普通函數(shù),就會(huì)報(bào)錯(cuò)。

async function dbFuc(db) {
 let docs = [{}, {}, {}];
 // 報(bào)錯(cuò)
 docs.forEach(function (doc) {
  await db.post(doc);
 });
}

上面代碼會(huì)報(bào)錯(cuò),因?yàn)?await 用在普通函數(shù)之中了。但是,如果將 forEach 方法的參數(shù)改成 async 函數(shù),也有問(wèn)題。

async function dbFuc(db) {
 let docs = [{}, {}, {}];

 // 可能得到錯(cuò)誤結(jié)果
 docs.forEach(async function (doc) {
  await db.post(doc);
 });
}

上面代碼可能不會(huì)正常工作,原因是這時(shí)三個(gè) db.post 操作將是并發(fā)執(zhí)行,也就是同時(shí)執(zhí)行,而不是繼發(fā)執(zhí)行。正確的寫(xiě)法是采用 for 循環(huán)。

async function dbFuc(db) {
 let docs = [{}, {}, {}];
 for (let doc of docs) {
  await db.post(doc);
 }
}

如果確實(shí)希望多個(gè)請(qǐng)求并發(fā)執(zhí)行,可以使用 Promise.all 方法。

async function dbFuc(db) {
 let docs = [{}, {}, {}];
 let promises = docs.map((doc) => db.post(doc));
 let results = await Promise.all(promises);
 console.log(results);
}
// 或者使用下面的寫(xiě)法
async function dbFuc(db) {
 let docs = [{}, {}, {}];
 let promises = docs.map((doc) => db.post(doc));
 let results = [];
 for (let promise of promises) {
  results.push(await promise);
 }
 console.log(results);
}

總結(jié)

以上所述是小編給大家介紹的js 中async 函數(shù)的含義和用法,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)歡迎給我留言,小編會(huì)及時(shí)回復(fù)大家的!

相關(guān)文章

  • JavaScript+CSS實(shí)現(xiàn)仿天貓側(cè)邊網(wǎng)頁(yè)菜單效果

    JavaScript+CSS實(shí)現(xiàn)仿天貓側(cè)邊網(wǎng)頁(yè)菜單效果

    這篇文章主要介紹了JavaScript+CSS實(shí)現(xiàn)仿天貓側(cè)邊網(wǎng)頁(yè)菜單效果,涉及javascript鼠標(biāo)事件及頁(yè)面元素動(dòng)態(tài)操作的實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-08-08
  • 理解JavaScript中的Proxy 與 Reflection API

    理解JavaScript中的Proxy 與 Reflection API

    這篇文章主要介紹了JavaScript中的Proxy 與 Reflection API的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)JavaScript,感興趣的朋友可以了解下
    2020-09-09
  • JS利用循環(huán)解決的一些常見(jiàn)問(wèn)題總結(jié)

    JS利用循環(huán)解決的一些常見(jiàn)問(wèn)題總結(jié)

    循環(huán)輸出問(wèn)題是面試中經(jīng)典的題目,一般會(huì)給出代碼,讓我們解釋原因,并給出若干解決方案,下面這篇文章主要給大家介紹了關(guān)于JS利用循環(huán)解決的一些常見(jiàn)問(wèn)題,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-08-08
  • 微信小程序之video組件視頻播放

    微信小程序之video組件視頻播放

    video控件是微信小程序提供的系統(tǒng)組件之一,用于實(shí)現(xiàn)播放視頻的功能,這篇文章主要給大家介紹了關(guān)于微信小程序之video組件視頻播放的相關(guān)資料,需要的朋友可以參考下
    2022-04-04
  • 如何利用JavaScript實(shí)現(xiàn)二叉搜索樹(shù)

    如何利用JavaScript實(shí)現(xiàn)二叉搜索樹(shù)

    這篇文章主要給大家介紹了關(guān)于如何利用JavaScript實(shí)現(xiàn)二叉搜索樹(shù)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • 使用electron制作滿(mǎn)屏心特效的示例代碼

    使用electron制作滿(mǎn)屏心特效的示例代碼

    這篇文章主要介紹了使用electron制作滿(mǎn)屏心特效的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-11-11
  • 運(yùn)用js實(shí)現(xiàn)圖層拖拽的功能

    運(yùn)用js實(shí)現(xiàn)圖層拖拽的功能

    js拖拽是常見(jiàn)的網(wǎng)頁(yè)效果,本文將從零開(kāi)始實(shí)現(xiàn)一個(gè)簡(jiǎn)單的js插件,下面和小編來(lái)一起學(xué)習(xí)一下吧
    2019-05-05
  • JavaScript實(shí)現(xiàn)表單驗(yàn)證案例

    JavaScript實(shí)現(xiàn)表單驗(yàn)證案例

    這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)表單驗(yàn)證案例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • js全屏事件fullscreenchange 實(shí)現(xiàn)全屏、退出全屏操作

    js全屏事件fullscreenchange 實(shí)現(xiàn)全屏、退出全屏操作

    這篇文章主要為大家詳細(xì)介紹了js全屏事件fullscreenchange,實(shí)現(xiàn)全屏、退出全屏操作,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-09-09
  • javascript中apply和call方法的作用及區(qū)別說(shuō)明

    javascript中apply和call方法的作用及區(qū)別說(shuō)明

    本篇文章主要是對(duì)javascript中apply和call方法的作用及區(qū)別進(jìn)行了介紹,需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助
    2014-02-02

最新評(píng)論