async 函数

1.ES2017 标准引入了 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) return 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,同时不需要co模块,更加语义化;

2.async 函数返回一个 Promise 对象,内部return语句返回的值,会成为then方法回调函数的参数;

async function f() {
return 'hello world';
} f().then(res => console.log(res))
// "hello world"

3.async 函数返回的 Promise 对象,必须等到内部所有 await 命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到 return 语句或者抛出错误。也就是说,只有 async 函数内部的异步操作执行完,才会执行 then 方法指定的回调函数;

4.如果 async 函数内部抛出错误,会导致返回的 Promise 对象变为 reject 状态,抛出的错误对象会被catch方法回调函数接收到;

async function f() {
throw new Error('出错了');
} f().then(
res => console.log(res),
err => console.log(err)
)
// Error: 出错了

5.await 命令后面是一个 Promise 对象。如果不是,会被转成一个立即 resolve 的 Promise 对象

async function f() {
return await 'Hello World';
} f().then(res => console.log(res))
// 'Hello World'

上述代码中,await命令的参数是 'Hello World',它被转成 Promise 对象,并立即 resolved

6.await 命令后面的 Promise 对象如果变为reject状态,则 reject 的参数会被 catch 方法的回调函数接收到

async function f() {
await Promise.reject('出错了');
} f().then(res => console.log(res))
.catch(err => console.log(err)) // 出错了

7.async 函数中 , 只要一个await语句后面的 Promise 变为reject,那么整个 async 函数都会中断执行;

async function f() {
await Promise.reject('出错了');
await Promise.resolve('hello world'); // 不会执行
} f(); // 出错了

8.如果我们希望即使前一个异步操作失败,也不要中断后面的异步操作。那我们可以将第一个 await 放在 try...catch 结构里面,这样不管这个异步操作是否成功,第二个 await 都会执行;

async function f() {
try {
await Promise.reject('出错了');
} catch(e) { }
return await Promise.resolve('hello world');
} f().then(res => console.log(res)) // hello world

或者是 await 后面的 Promise 对象再跟一个 catch 方法,处理前面可能出现的错误:

async function f() {
await Promise.reject('出错了')
.catch(err => console.log(err));
return await Promise.resolve('hello world');
} f()
.then(res => console.log(res))
// 出错了
// hello world

9.如果 await 后面的异步操作出错,那么等同于 asyn c函数返回的 Promise 对象被 rejected:

async function f() {
await new Promise(function (resolve, reject) {
throw new Error('出错了');
});
} f().then(res => console.log(res))
.catch(err => console.log(err))
// Error:出错了

10.为了防止出错,做法也是将其放在try...catch代码块之中,并且如果有多个await命令,可以统一放在try...catch结构中。

async function f() {
try {
await new Promise(function (resolve, reject) {
throw new Error('出错了');
});
} catch(e) {
}
return await('hello world');
} f().then( res => console.log(res) )
// 'hello world'

11.使用 await 要注意以下几点 :

  • await 命令后面的 Promise 对象,运行结果可能是 rejected,所以最好把 await 命令放在 try...catch 代码块中

     async function myFunction() {
    try {
    await operations();
    } catch (err) {
    console.log(err);
    }
    } // 另一种写法 async function myFunction() {
    await operations()
    .catch(function (err) {
    console.log(err);
    });
    }
  • 多个 await 命令后面的异步操作,如果不存在继发关系(即互不依赖),最好让它们同时触发,缩短程序的执行时间

     // 写法一
    let [foo, bar] = await Promise.all([getFoo(), getBar()]); // 写法二
    let fooPromise = getFoo();
    let barPromise = getBar();
    let foo = await fooPromise;
    let bar = await barPromise;
  • await 命令只能用在 async 函数之中,如果用在普通函数,就会报错

     async function func(db) {
    let docs = [{}, {}, {}]; // 报错
    docs.forEach(function (doc) {
    await db.post(doc);
    });
    }

ES6必知必会 (八)—— async 函数的更多相关文章

  1. 2015 前端[JS]工程师必知必会

    2015 前端[JS]工程师必知必会 本文摘自:http://zhuanlan.zhihu.com/FrontendMagazine/20002850 ,因为好东东西暂时没看懂,所以暂时保留下来,供以 ...

  2. [ 学习路线 ] 2015 前端(JS)工程师必知必会 (2)

    http://segmentfault.com/a/1190000002678515?utm_source=Weibo&utm_medium=shareLink&utm_campaig ...

  3. mysql必知必会——GROUP BY和HAVING

    mysql必知必会——GROUP BY和HAVING 创建表结构 create table `employ_info` ( `id` int(11) NOT NULL AUTO_INCREMENT, ...

  4. 闻道Go语言,6月龄必知必会

    大家好,我是马甲哥, 学习新知识, 我的策略是模仿-->归纳--->举一反三, 在同程倒腾Go语言一年有余,本次记录<闻道Go语言,6月龄必知必会>,形式是同我的主力语言C#做 ...

  5. 读书笔记汇总 - SQL必知必会(第4版)

    本系列记录并分享学习SQL的过程,主要内容为SQL的基础概念及练习过程. 书目信息 中文名:<SQL必知必会(第4版)> 英文名:<Sams Teach Yourself SQL i ...

  6. 《MySQL 必知必会》读书总结

    这是 <MySQL 必知必会> 的读书总结.也是自己整理的常用操作的参考手册. 使用 MySQL 连接到 MySQL shell>mysql -u root -p Enter pas ...

  7. 《SQL必知必会》学习笔记(一)

    这两天看了<SQL必知必会>第四版这本书,并照着书上做了不少实验,也对以前的概念有得新的认识,也发现以前自己有得地方理解错了.我采用的数据库是SQL Server2012.数据库中有一张比 ...

  8. SQL 必知必会

    本文介绍基本的 SQL 语句,包括查询.过滤.排序.分组.联结.视图.插入数据.创建操纵表等.入门系列,不足颇多,望诸君指点. 注意本文某些例子只能在特定的DBMS中实现(有的已标明,有的未标明),不 ...

  9. 《MySQL必知必会》[01] 基本查询

    <MySQL必知必会>(点击查看详情) 1.写在前面的话 这本书是一本MySQL的经典入门书籍,小小的一本,也受到众多网友推荐.之前自己学习的时候是啃的清华大学出版社的计算机系列教材< ...

  10. mysql必知必会

    春节放假没事,找了本电子书mysql必知必会敲了下.用的工具是有道笔记的markdown文档类型. 下面是根据大纲已经敲完的章节,可复制到有道笔记的查看,更美观. # 第一章 了解SQL## 什么是S ...

随机推荐

  1. 常用php操作redis命令整理(四)SET类型

    SADD 将一个或多个member元素加入到集合key当中.(从左侧插入,最后插入的元素在0位置),集合中已经存在TK 则返回false,不存在添加成功 返回true <?php var_dum ...

  2. 20135320赵瀚青LINUX期中总结

    期中总结 心得与体会 本学期的LINUX内核这门课程已经进行了一半,这门课的学习方法和上个学期深入理解计算机系统的方式差不多,所以也没有特别多不适应,LINUX内核在我看来,就是理解一个操作系统是如何 ...

  3. 搭建docker hadoop环境

    目录 搭建Docker-Hadoop基础环境 简介 步骤 搭建Docker image ..待续 注释 搭建Docker-Hadoop基础环境 简介 因为很难真正的有一个集群环境.在一般的条件下想要模 ...

  4. (Matlab)GPU计算简介,及其与CPU计算性能的比较

    1.GPU与CPU结构上的对比 2.GPU能加速我的应用程序吗? 3.GPU与CPU在计算效率上的对比 4.利用Matlab进行GPU计算的一般流程 5.GPU计算的硬件.软件配置 5.1 硬件及驱动 ...

  5. Anaconda中常用的用法

    Anaconda中常用的用法 conda 是开源包(packages)和虚拟环境(environment)的管理系统. packages 管理: 可以使用 conda 来安装.更新 .卸载工具包 ,并 ...

  6. install ros-indigo-camera-info-manager

    CMake Warning at /opt/ros/indigo/share/catkin/cmake/catkinConfig.cmake: (find_package): Could not fi ...

  7. Strategy(策略)

    意图: 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换.本模式使得算法可独立于使用它的客户而变化. 适用性: 许多相关的类仅仅是行为有异.“策略”提供了一种用多个行为中的一个行为来配置 ...

  8. Qt5_vs2013_error_C2001: 常量中有换行符__资料

    ZC: Win7x64 + Qt551(x86) + vs2013(x86) ZC: 问题:UTF-8 在源码文件中有中文时,有时会报编译错误:C2001 & C2143 分析: --> ...

  9. thinkphp3.2笔记(3)视图渲染 模板的赋值与显示 系统变量

    一  视图 1  视图渲染 渲染模板输出最常用的是使用display方法,调用格式:display('[模板文件]'[,'字符编码'][,'输出类型'])模板文件的写法支持下面几种:用法 描述不带任何 ...

  10. Java实现时钟小程序【代码】

    哎,好久没上博客园发东西了,上一次还是两个月前的五一写的一篇计算器博客,不过意外的是那个程序成了这学期的Java大作业,所以后来稍微改了一下那个程序就交了上去,这还是美滋滋.然后五月中旬的时候写了一个 ...