之前也学过,只是没有学好,公司现在用的都是async函数 , 所以决定把它弄懂。最近看了看阮一峰的博客,做下记录。

异步I/O不就是读取一个文件吗,干嘛要搞得这么复杂?异步编程的最高境界,就是根本不用关心它是不是异步。

先讲讲Promise函数

举个例子:

 function f1(){
return new Promise(resolve =>{
setTimeout(() => {
console.log('第一步')
//告诉外界第一步成功了
resolve('第一步完成')
}, );
})
}
f1().then((res)=>{
console.log(res);
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('第二步');
reject('第二步失败')
},)
})
}).catch(res=>{
console.log(res);
})

async

 (async function(){
//await表示这行代码是一个异步操作
//下面的代码会在这个异步操作之后执行
// -->这里的异步操作执行完毕其实就是resolve
//(必须要resolve才能执行完毕)
await f1()
const returno = await f1() //resolve作为返回值来接收
console.log(returno);
console.log('第二步');
await f1()
await f1()
console.log('第三步');
})()

错误捕捉 只能用老一套的try catch

 function f1(){
return new Promise((resolve,reject) =>{
setTimeout(() => {
console.log('你好')
//告诉外界第一步成功了
// resolve('第一步完成')
reject('失败')
}, );
})
}
(async function(){
try{
const res = await f1()// 返回值,是成功的返回值
console.log(res);
}catch(e){
console.log(e);
}
})()

 

一、async 函数是什么

一句话,async 函数就是 Promise 函数的语法糖。

有一个 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 函数-----------------解决异步操作隧道的亮光的更多相关文章

  1. async函数基础

    async函数 含义 异步操作的函数,一句话,async函数就是generator函数的语法糖. 用法 async函数会将generator函数的星号(*)替换成async,将yield替换成awai ...

  2. JS异步操作新体验之 async函数

    1.初识 async 函数   ES6中提供了两个很好的解决异步操作的方案 Promise 和 Generator,ES2017标准中引入的 async 函数就是建立在 Promise 和 Gener ...

  3. 利用async和await异步操作解决node.js里面fs模块异步读写,同步结果的问题

    async await 解决异步问题,这两个关键字是es7提出的,所以测试,node和浏览器版本提高一些 async await 操作基于promise实现的 async await这两个关键字是一起 ...

  4. JavaScript ES7 中使用 async/await 解决回调函数嵌套问题

    原文链接:http://aisk.me/using-async-await-to-avoid-callback-hell/ JavaScript 中最蛋疼的事情莫过于回调函数嵌套问题.以往在浏览器中, ...

  5. async 函数的含义和用法

    Generator函数的含义与用法 Thunk函数的含义与用法 co函数库的含义与用法 async函数的含义与用法 一.终极解决 异步操作是 JavaScript 编程的麻烦事,麻烦到一直有人提出各种 ...

  6. async 函数学习笔记

    async函数就是Generator函数的语法糖. var fs = require('fs'); var readFile = function (fileName) { return new Pr ...

  7. es6学习笔记-async函数

    1 前情摘要 前段时间时间进行项目开发,需求安排不是很合理,导致一直高强度的加班工作,这一个月不是常说的996,简直是936,还好熬过来了.在此期间不是刚学会了es6的promise,在项目有用到pr ...

  8. 17.async 函数

    async 函数 async 函数 含义 ES2017 标准引入了 async 函数,使得异步操作变得更加方便. async 函数是什么?一句话,它就是 Generator 函数的语法糖. 前文有一个 ...

  9. ES6的新特性(18)——async 函数

    async 函数 含义 ES2017 标准引入了 async 函数,使得异步操作变得更加方便. async 函数是什么?一句话,它就是 Generator 函数的语法糖. 前文有一个 Generato ...

随机推荐

  1. (C/C++学习)14.C语言字符串处理函数(二)

    说明:上节着重解释了字符串处理的库函数处理,这节将针对一些常用的需求,进行非库函数的处理. 一.去除某一个字符串中的某个字符 1.去除字符串右边的空格 void trimStrRightSpace(c ...

  2. MyBatis 的基本要素—核心配置文件

    MyBatis 核心配置文件( mybatis-config.xml),该文件配置了 MyBatis 的一些全局信息,包含数据库连接信息和 MyBatis 运行时所需的各种特性,以及设置和影响 MyB ...

  3. mysql批量替换某个字段的部分内容

    举例说明 有数据表person,结构如下 id name urls 1 张三 xh.jpg 2 李四 xh.jpg 3 王五 3.jpg 需求:将urls字段中的xh替换为id字段的值 语句: UPD ...

  4. noip模拟赛 街灯

    分析:对于前30%的数据直接暴力模拟即可,对于另外30%的数据,因为每次的p是一样的,所以可以用莫队来维护,先离散化一下,再用一个桶统计次数. 100%的做法和之前做过的一道模拟赛题很像,当模数很小的 ...

  5. Codeforces 303A(构造)

    题意:对0到(n-1)这n个数进行全排列.请找出三个全排列a.b.c,使得“a与b的对应元素的和”与“c的对应元素”对模n同余,无解输出-1.(n<=1e5) 分析:n为奇数有解,n为偶数无解 ...

  6. CentOS设置程序开机启动程序/服务的方法(转)

    注意:CentOS 6下基本没什么问题,CentOS 7估计不一定能行. 在CentOS系统下,主要有两种方法设置自己安装的程序开机启动. 1.把启动程序的命令添加到/etc/rc.d/rc.loca ...

  7. Animations动画和Keyframes关键帧

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. mysql模糊查询语句

    select * from tbl_actor where first_char like 'p%' order by first_char;

  9. Node: 在Mac中离线安装Sqlite3

    最近在安装db-migrate的时候,有一个依赖包sqlite3怎样都安装不了,检查下来应该是由于node_sqlit3.node文件无法从Amazon下载导致(源码安装也报错,没有研究过原因).于是 ...

  10. 最老程序猿创业开发实训1---Android应用架构之MVC

    我们都知道Android中基本组件是Activity,每一个界面都是一个Activity,自从2.3版本号開始.又添加了Fragment组件,提供了适应于各种屏幕方法.可是因为Android系统仅仅是 ...