js 中async

一、終極解決

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

從最早的回調函數,到 Promise 對象,再到 Generator 函數,每次都有所改進,但又讓人覺得不徹底。它們都有額外的復雜性,都需要理解抽象的底層運行機制。

異步I/O不就是讀取一個文件嗎,干嘛要搞得這么復雜?異步編程的最高境界,就是根本不用關心它是不是異步。
async 函數就是隧道盡頭的亮光,很多人認為它是異步操作的終極解決方案。

二、async 函數是什么?

一句話,async 函數就是 Generator 函數的語法糖。

前文有一個 Generator 函數,依次讀取兩個文件。

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());
};

寫成 async 函數,就是下面這樣。

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

一比較就會發現,async 函數就是將 Generator 函數的星號(*)替換成 async,將 yield 替換成 await,僅此而已。

三、async 函數的優點

async 函數對 Generator 函數的改進,體現在以下三點。

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

var result = asyncReadFile();

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

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

四、async 函數的實現

async 函數的實現,就是將 Generator 函數和自動執行器,包裝在一個函數里。

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

所有的 async 函數都可以寫成上面的第二種形式,其中的 spawn 函數就是自動執行器。

下面給出 spawn 函數的實現,基本就是前文自動執行器的翻版。

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 函數是非常新的語法功能,新到都不屬于 ES6,而是屬于 ES7。目前,它仍處于提案階段,但是轉碼器 Babel 和 regenerator 都已經支持,轉碼后就能使用。

五、async 函數的用法

同 Generator 函數一樣,async 函數返回一個 Promise 對象,可以使用 then 方法添加回調函數。當函數執行的時候,一旦遇到 await 就會先返回,等到觸發的異步操作完成,再接著執行函數體內后面的語句。
下面是一個例子。

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

上面代碼是一個獲取股票報價的函數,函數前面的async關鍵字,表明該函數內部有異步操作。調用該函數時,會立即返回一個Promise對象。
下面的例子,指定多少毫秒后輸出一個值。

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"。

六、注意點

await 命令后面的 Promise 對象,運行結果可能是 rejected,所以最好把 await 命令放在 try…catch 代碼塊中。

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

await 命令只能用在 async 函數之中,如果用在普通函數,就會報錯。

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

上面代碼會報錯,因為 await 用在普通函數之中了。但是,如果將 forEach 方法的參數改成 async 函數,也有問題。

async function dbFuc(db) {let docs = [{}, {}, {}];// 可能得到錯誤結果docs.forEach(async function (doc) {await db.post(doc);});
}

上面代碼可能不會正常工作,原因是這時三個 db.post 操作將是并發執行,也就是同時執行,而不是繼發執行。正確的寫法是采用 for 循環。

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

如果確實希望多個請求并發執行,可以使用 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);
}
// 或者使用下面的寫法
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);
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/249385.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/249385.shtml
英文地址,請注明出處:http://en.pswp.cn/news/249385.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python查找指定文件

在當前目錄以及當前目錄的所有子目錄下查找文件名包含指定字符串的文件,并打印出相對路徑: import os testfiles [] testfilepaths [] L len(os.path.abspath(.))def searchfile(path):for item in os.listdir(path):if os.path.isdir(os.path.join(p…

搭建Mock Server

搭建Mock Server 1.為什么要搭建mock-server? 為了更好的分工合作,讓前端能在不依賴后端環境的情況下進行開發,其中一種手段就是為前端開發者提供一個 web 容器,這個本地環境就是 mock-server。 目前很多前端 mock 數據的方案的…

請問1到10000之前,有多少升數字?(華圖教育面試題)

升數字就是從左向右讀,數值是依次上升的即可,比如123,1256,1389,但是1123,165就不是。以下是我的思路 public static void main(String[] args) {/*** 【請問1到10000之前,有多少升數字&#xf…

crm 一級菜單排序,二級菜單選中并且展開,非菜單權限的歸屬,權限粒度控制到按鈕級別...

排序 /rbac/templatetags/rbac.py from django import template from django.conf import settings import re from collections import OrderedDict register template.Library()register.inclusion_tag(rbac/menu.html) def menu(request):ordered_dictOrderedDict()menu_d…

Maven工程的多模塊

一個大項目需要一個團隊來完成,然后一個大型項目就拆分成幾塊來同時開發,節省時間,提高效率. 大致分為以下幾個模塊(僅是自身經歷): 依賴管理工程模塊:一般現在開發都是以maven來管理jar包,方便.所以整個工程的依賴統一放在一個單獨工程中,一般叫做父工程xxx-parent. 注意事項…

《淺談架構之路:前后端分離模式》

前言:分離模式 對前后端分離研究了一段時間,恰逢公司有一個大項目決定嘗試使用前后端分離模式進行,便參與其中。該項目從2016年初立項至今,平平穩穩得度過,但也涌現出越來越多的問題,絕對不是說前后端分離模…

查詢語句

1.基本查詢語句 1.1 語法: SELECT 屬性列表 FROM 表名或視圖列表 WHERE 條件表達式1 GROUP BY 屬性名1 | HAVING 條件表達式2 ORDER BY 屬性名2 ASC DESC 2.單表查詢 1.應用:查詢表中所有的記錄 2.查詢指定字段:查詢表中所有name字段的記錄 …

Nodejs+Koa2+云服務ECS 開發微信公眾號(一)之環境配置

硬件準備工作 1. 本人采用阿里云的云服務器,購買了入門級云服務ECS(293元每年); 2.針對服務器進行認證,設置個人服務器密碼; 3.購買數據盤,并將其掛載于云服務器之上(建議掛載在/…

中文詞頻統計與詞云生成

本次作業來源于:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE1/homework/2822 中文詞頻統計 1. 下載一長篇中文小說。 下載長篇小說《西游記》 本次作業小說保存在txt文檔:xyj.txt 2. 從文件讀取待分析文本。 xyj open(rF:/xyj.txt,r,encodingutf-8)…

java SWT Browser實現瀏覽器功能并運行JavaScript代碼

一、創建簡單的瀏覽器 import org.eclipse.swt.*; import org.eclipse.swt.browser.*; import org.eclipse.swt.layout.*; import org.eclipse.swt.widgets.*;public class Myswt3 {public static void main(String [] args) {Display display new Display();final Shell she…

[JZOJ5866]【NOIP2018模擬9.13】指引

Description Input Output Sample Input 6 3 2 0 3 1 1 3 4 2 0 4 5 5 Sample Output 2 Data Constraint Hint 貪心,把旅行者和出口的x坐標降序排序。 然后從前往后掃,如果是出口,就把y坐標插進set里,如果是旅行者,就查…

scrapy框架之遞歸解析和post請求

今日概要 遞歸爬取解析多頁頁面數據scrapy核心組件工作流程scrapy的post請求發送今日詳情 1.遞歸爬取解析多頁頁面數據 - 需求:將糗事百科所有頁碼的作者和段子內容數據進行爬取切持久化存儲 - 需求分析:每一個頁面對應一個url,則scrapy工程需…

SmartGit 過期解決方案之 非商業版本安裝使用

作為前端開發的小伙伴一定有這樣的困惑,自己在日常的團隊協作配合時,提交代碼和解決沖突是我們最頭疼的問題,但是又不喜歡使用Eclipse或者IDEA這種超級占內存的編輯器,使用Git命令又是那么捉襟見肘,所以有一個好用的輕…

HDU6438 Buy and Resell 解題報告(一個有趣的貪心問題的嚴格證明)

寫在前面 此題是一個很容易想到的貪心題目,但是正確性的證明是非常復雜的。然而,目前網上所有題解并未給出本題貪心算法的任何正確性證明,全部僅停留在描述出一個貪心算法。本著對算法與計算機科學的熱愛(逃)&#xff…

Webpack不生成index.html

沒有導出你的最后2個插件,并且沒有指定html文件名dist,因為HtmlWebpackPlugin應該生成相對于path,下面是固定配置: var path require(path)var webpack require(webpack)var HtmlWebpackPlugin require(html-webpack-plugin);m…

CSS3筆記之定位篇(一)relative

知識點1:relative和absolute relative: 相對自身,并會限制內部absolute元素層疊 absolute: 相對容器,并受到父類容器relative的影響,比如:overflow:hidden/scroll fixed: 不受relative限制,只受z-index的…

洛谷P3066 [USACO12DEC]逃跑的BarnRunning Away From…

題面鏈接 一句話題意:給出以1號點為根的一棵有根樹,問每個點的子樹中與它距離小于等于l的點有多少個。 我:似乎并不好做啊。。。看了題解后大霧。。。 sol:考慮樹上差分,對于一個點,在他那個位置&#xff0…

vue使用webPack打包發布后頁面顯示空白

今天筆者將打包后,進行訪問,訪問到index.html,但是出現的是空白頁。 打包命令:npm run build,打包后的文件如下: 這是因為index.html中引入的css ,js 的路徑不對:如下圖 這個是因為webpack打包的時候引入…

第一次實驗報告

c程序實驗報告 姓名:黃志乾 實驗地點:教學樓514教室 實驗時間:3月19日實驗項目: 1、字符與ASCII碼 2、運算符與表達式的應用 3、順序結構應用程序 4、數學函數的算法描述 5、雞兔同籠的算法描述 6、確定坐標的算法描述…

Mac下Idea安裝Git報錯Xcrun問題的解決

使用過IDEA的小伙伴都知道,它和我們之前用過的Eclipse一樣強大,或者比他更強大。當它配合的Mac使用時,就會變得更得心應手,少去很多環境配置的環節。其中最典型的就是Git 由于Mac自帶就安裝了git, 大家可以通過終端輸入命令“git…