async 函数的含义和用法
- Generator函数的含义与用法
- Thunk函数的含义与用法
- co函数库的含义与用法
- 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);
}
async 函数的含义和用法的更多相关文章
- JS前端重点 -- Generator 函数的含义与用法
Generator 函数的含义与用法 1.generator http://www.ruanyifeng.com/blog/2015/04/generator.html http://it.taocm ...
- 转: ES6异步编程:Thunk函数的含义与用法
转: ES6异步编程:Thunk函数的含义与用法 参数的求值策略 Thunk函数早在上个世纪60年代就诞生了. 那时,编程语言刚刚起步,计算机学家还在研究,编译器怎么写比较好.一个争论的焦点是&quo ...
- 转: ES6异步编程:Generator 函数的含义与用法
转: ES6异步编程:Generator 函数的含义与用法 异步编程对 JavaScript 语言太重要.JavaScript 只有一根线程,如果没有异步编程,根本没法用,非卡死不可. 以前,异步编程 ...
- Generator 函数的含义与用法
Generator 函数是协程在 ES6 的实现,最大特点就是可以交出函数的执行权(即暂停执行). function* gen(x){ var y = yield x + 2; return y; } ...
- opencv学习笔记——minMaxIdx函数的含义及用法
opencv中有时需要对Mat数据需要对其中的数据求取最大值和最小值.opencv提供了直接的函数 CV_EXPORTS_W void minMaxLoc(InputArray src, CV_OUT ...
- async函数解析
转载请注明出处:async函数解析 async函数是基于Generator函数实现的,也就是说是Generator函数的语法糖.在之前的文章有介绍过Generator函数语法和异步应用,如果对其不了解 ...
- 转: ES6异步编程: co函数库的含义与用法
转: ES6异步编程: co函数库的含义与用法 co 函数库是著名程序员 TJ Holowaychuk 于2013年6月发布的一个小工具,用于 Generator 函数的自动执行. 比如,有一个 Ge ...
- 浅谈async函数await用法
今天状态不太好,睡久了懵一天. 以前只是了解过async函数,并还没有很熟练的运用过,所以先开个坑吧,以后再结合实际来更新下,可能说的有些问题希望大家指出. async和await相信大家应该不陌生, ...
- 17.async 函数
async 函数 async 函数 含义 ES2017 标准引入了 async 函数,使得异步操作变得更加方便. async 函数是什么?一句话,它就是 Generator 函数的语法糖. 前文有一个 ...
随机推荐
- smartJQueryZoom(smartZoom) 的使用方法
smartZoom 是一个我很喜欢用的库. 但是这个库有一些不完善的地方. 比如BUG. 比如使用上可能遇到的问题. <article> <div id="zoom_box ...
- 数据湖应用解析:Spark on Elasticsearch一致性问题
摘要:脏数据对数据计算的正确性带来了很严重的影响.因此,我们需要探索一种方法,能够实现Spark写入Elasticsearch数据的可靠性与正确性. 概述 Spark与Elasticsearch(es ...
- 题解 洛谷 P3247 【[HNOI2016]最小公倍数】
题意可以转化为是否能找一条从\(u\)到\(v\)的路径,经过的边的\(a\)和\(b\)的最大值恰好都是询问所给定的值. 若只有\(a\)的限制,可以将询问离线,对边和询问都从小到大排序,然后双指针 ...
- 学习2周C++的收获
学习2周C++的收获 首先,C++是一种实用性很强的程序设计语言.它使用起来灵活.方便,运算符丰富,有结构化的层次…… 那么,我学习这个语言主要是为了参加信息学奥林匹克竞赛,这不仅要熟练地掌握一门语言 ...
- spring学习(一)spring简介
Spring简介: Spring 框架是 Java 应用最广的框架,它的成功来源于理念,而不是技术本身,它的理念包括 IoC (Inversion of Control,控制反转) 和 AOP(Asp ...
- python基础--函数全解析(2)
函数的重点知识补充 (1)补充的两个小知识点(global,nonlocal) 1.global的使用 我们在补充这两个知识点之前,我们先看一下下面这个例子: a = 1 def func(): pr ...
- 01 . Go框架之Beego简介部署及程序流程分析
Beego简介 beego是一个使用Go语言来开发WEB引用的GoWeb框架,该框架起始于2012年,由一位中国的程序员编写并进行公开,其目的就是为大家提供一个高效率的web应用开发框架.该框架采用模 ...
- mybatis之if判断
今天使用mybatis开发公司中台项目踩的一个坑,分享并记录一下 踩坑前因:因项目中比较多状态字段,用了大量的Integer 0和1进行判断 在功能做完后只是粗略的点了下觉得没多大问题(来自程序员强大 ...
- setTimeout、clearTimeout、setInterval
setTimeout(cb, ms) setTimeout(cb, ms) 全局函数在指定的毫秒(ms)数后执行指定函数(cb).:setTimeout() 只执行一次指定函数. 返回一个代表定时器的 ...
- 使用Spring Validation优雅地校验参数
写得好的没我写得全,写得全的没我写得好 引言 不知道大家平时的业务开发过程中 controller 层的参数校验都是怎么写的?是否也存在下面这样的直接判断? public String add(Use ...