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.mzph.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…