在实际开发中总会遇到许多异步的问题,最常见的场景便是接口请求之后一定要等一段时间才能得到结果,如果遇到多个接口前后依赖,那么问题就变得复杂。大家都一直在尝试使用更好的方案来解决这些问题。最开始只能利用回调函数,后来开始有人使用Promise的思维来搞定。到ES6中开始支持原生的Promise,引入Generator函数。

直到ES7,有了async/await

这是一个用同步的思维来解决异步问题的方案。

我想很多人可能还不太分得清同步与异步的区别。如果你已经彻底了解了事件循环,那么想必对异步的概念应该非常了解。当我们发出了请求,并不会等待响应结果,而是会继续执行后面的代码,响应结果的处理在之后的事件循环中解决。那么同步的意思,就是等结果出来之后,代码才会继续往下执行。

我们可以用一个两人问答的场景来比喻异步与同步。A向B问了一个问题之后,不等待B的回答,接着问下一个问题,这是异步。A向B问了一个问题之后,然后就笑呵呵的等着B回答,B回答了之后他才会接着问下一个问题,这是同步。

那么我们先记住这个特点,async/await使用同步的思维,来解决异步的问题。

在继续分析它的语法与使用之前,我们先介绍一下如何在我们的开发环境中支持该语法。

如果你已经知道如何配置,可跳过

一、如何在自己的开发环境中支持async/await语法

这里主要介绍两种方式。

1. webpack中支持该语法

首先在当前项目中使用npm下载babel-loader

> npm install babel-loader --save-dev

然后在配置文件webpack.confing.dev.js中配置,在module.exports.module.rules中添加如下配置元素即可。

  {
test: /\.(js|jsx)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
cacheDirectory: true,
},
},

如果你使用最新版本的create-react-app或者vue-cli来构建你的代码,那么它们应该已经支持了该配置。

2. gulp中支持该语法

首先安装gulp插件

> npm install gulp-babel --save-dev

然后编写任务

var gulp = require('gulp');
var babel = require('gulp-babel'); gulp.task('babel', function() {
return gulp.src('src/app.js')
.pipe(babel())
.pipe(gulp.dest('dist'));
});

二、如何使用

async函数是Generator的一个语法糖。如果你不知道Generator是什么函数也没有关系,我们只需要知道async函数实际上返回的是一个Promise对象即可。

async function fn() {
return 30;
} // 或者
const fn = async () => {
return 30;
}

在声明函数时,前面加上关键字async,这就是async的用法。当我们用console.log打印出上面声明的函数fn,我们可以看到如下结果:

console.log(fn());

// result
Promise = {
__proto__: Promise,
[[PromiseStatus]]: "resolved",
[[PromiseValue]]: 30
}

很显然,fn的运行结果其实就是一个Promise对象。因此我们也可以使用then来处理后续逻辑。

fn().then(res => {
console.log(res); // 30
})

await的含义为等待。意思就是代码需要等待await后面的函数运行完并且有了返回结果之后,才继续执行下面的代码。这正是同步的效果。

但是我们需要注意的是,await关键字只能在async函数中使用。并且await后面的函数运行后必须返回一个Promise对象才能实现同步的效果。

当我们使用一个变量去接收await的返回值时,该返回值为Promise中resolve出来的值(也就是PromiseValue)。

 // 定义一个返回Promise对象的函数
function fn() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(30);
}, 1000);
})
} // 然后利用async/await来完成代码
const foo = async () => {
const t = await fn();
console.log(t);
console.log('next code');
} foo(); // result:
//
// next code

运行这个例子我们可以看出,当在async函数中,运行遇到await时,就会等待await后面的函数运行完毕,而不会直接执行next code

如果我们直接使用then方法的话,想要达到同样的结果,就不得不把后续的逻辑写在then方法中。

const foo = () => {
return fn().then(t => {
console.log(t);
console.log('next code');
})
} foo();

很显然如果使用async/await的话,代码结构会更加简洁,逻辑也更加清晰。

异常处理

在Promise中,我们知道是通过catch的方式来捕获异常。而当我们使用async时,则通过try/catch来捕获异常。

 function fn() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('some error.');
}, 1000);
})
} const foo = async () => {
try {
await fn();
} catch (e) {
console.log(e); // some error
}
} foo();

如果有多个await函数,那么只会返回第一个捕获到的异常。

 function fn1() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('some error fn1.');
}, 1000);
})
}
function fn2() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('some error fn2.');
}, 1000);
})
} const foo = async () => {
try {
await fn1();
await fn2();
} catch (e) {
console.log(e); // some error fn1.
}
} foo();
实践

在实践中我们遇到异步场景最多的就是接口请求,那么这里就以jquery中的$.get为例简单展示一下如何配合async/await来解决这个场景。

// 先定义接口请求的方法,由于jquery封装的几个请求方法都是返回Promise实例,因此可以直接使用await函数实现同步
 const getUserInfo = () => $.get('xxxx/api/xx');

 const clickHandler = async () => {
try {
const resp = await getUserInfo();
// resp为接口返回内容,接下来利用它来处理对应的逻辑
console.log(resp); // do something
} catch (e) {
// 处理错误逻辑
}
}

为了保证逻辑的完整性,在实践中try/catch必不可少。总之,不处理错误逻辑的程序员不是好程序员。

与Promise相比,个人认为async/await有一定的简洁性,但也并非就比Promise有绝对的优势,因此只能算是提供了另外一种同样很棒的方式,至于大家学习之后选择哪种方式来解决自己的问题,我认为这仅仅只是个人的喜好问题。

附件2:async/await的更多相关文章

  1. async & await 的前世今生(Updated)

    async 和 await 出现在C# 5.0之后,给并行编程带来了不少的方便,特别是当在MVC中的Action也变成async之后,有点开始什么都是async的味道了.但是这也给我们编程埋下了一些隐 ...

  2. [.NET] 利用 async & await 的异步编程

    利用 async & await 的异步编程 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/5922573.html  目录 异步编程的简介 异 ...

  3. [.NET] 怎样使用 async & await 一步步将同步代码转换为异步编程

    怎样使用 async & await 一步步将同步代码转换为异步编程 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/6079707.html  ...

  4. [.NET] 利用 async & await 进行异步 IO 操作

    利用 async & await 进行异步 IO 操作 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/6082673.html  序 上次,博主 ...

  5. [C#] 走进异步编程的世界 - 开始接触 async/await

    走进异步编程的世界 - 开始接触 async/await 序 这是学习异步编程的入门篇. 涉及 C# 5.0 引入的 async/await,但在控制台输出示例时经常会采用 C# 6.0 的 $&qu ...

  6. ASP.NET 中的 Async/Await 简介

    本文转载自MSDN 作者:Stephen Cleary 原文地址:https://msdn.microsoft.com/en-us/magazine/dn802603.aspx 大多数有关 async ...

  7. C# async/await 使用总结

    今天搞这两个关键字搞得有点晕,主要还是没有彻底理解其中的原理. 混淆了一个调用异步方法的概念: 在调用异步方法时,虽然方法返回一个 Task,但是其中的代码已经开始执行.该方法在调用时,即刻执行了一部 ...

  8. 【转】async & await 的前世今生

    async 和 await 出现在C# 5.0之后,给并行编程带来了不少的方便,特别是当在MVC中的Action也变成async之后,有点开始什么都是async的味道了.但是这也给我们编程埋下了一些隐 ...

  9. async & await 的前世今生

    async 和 await 出现在C# 5.0之后,给并行编程带来了不少的方便,特别是当在MVC中的Action也变成async之后,有点开始什么都是async的味道了.但是这也给我们编程埋下了一些隐 ...

随机推荐

  1. C++--浅谈开发系统的经验

    最近写了不少类了,从垃圾代码爬坑,虽然还是很垃圾,但是照葫芦画瓢,有几分神韵.在这里总结一下,写类的经验教训. 第一步 分析: 当拿到一个要求时,要先去考虑怎样一个类到底该实现什么样的功能,有什么样的 ...

  2. SpringBoot上传文件大小限制

    SpringBoot默认上传文件大小不能超过1MB,超过之后会报以下异常: org.apache.tomcat.util.http.fileupload.FileUploadBase$FileSize ...

  3. Android | 带你零代码实现安卓扫码功能

    目录 小序 背景介绍 前期准备 开始搬运 结语 小序   这是一篇纯新手教学,本人之前没有任何安卓开发经验(尴尬),本文也不涉及任何代码就可以使用一个扫码demo,华为scankit真是新手的福音-- ...

  4. 【MIT6.828】centos7下使用Qemu搭建xv6运行环境

    title:[MIT6.828]centos7下使用Qemu搭建xv6运行环境 date: "2020-05-05" [MIT6.828]centos7下搭建xv6运行环境 1. ...

  5. 系统基础优化 vim

    系统基础优化 vim 1系统基础优化 (CPU-lscpu 内存-free 磁盘-df 负载-w/uptime) 1.1 系统基础优化 准备工作:如何查看系统的信息 (1)cat /etc/redha ...

  6. Spring 框架介绍 [Spring 优点][Spring 应用领域][体系结构][目录结构][基础 jar 包]

    您的"关注"和"点赞",是信任,是认可,是支持,是动力...... 如意见相佐,可留言. 本人必将竭尽全力试图做到准确和全面,终其一生进行修改补充更新. 目录 ...

  7. node基础知识-说说对node的理解

    一.说说你对node的理解 从定义+特点+作用来说对node的理解 定义:node是基于Chrmo v8引擎的JavaScript运行环境; 特点:具有事件驱动,非阻塞I/O模型,高并发和轻量级,单线 ...

  8. 王颖奇 201771010129《面向对象程序设计(java)》第四周学习总结

    实验四 类与对象的定义及使用 实验时间 2018-9-20 1.目的与要求 学习目标 掌握类与对象的基础概念,理解类与对象的关系: 掌握对象与对象变量的关系: 掌握预定义类的基本使用方法,熟悉Math ...

  9. Excel开始,Excel结束,R语言居中

    入职.离职,总公司调往分公司,分公司调往总公司,每月社保.公积金和上月比较有增减.税局导出的为Excel文件,需要和记录对照一番. 用Excel处理,那就是姓名粘贴为两列,条件格式-重复值,没变色的为 ...

  10. [hdu5218]DP-约瑟夫环变形

    题意:n个人围成一圈,另外一个人最开始站在第一个人前面,每次从集合s里面随机选一个数x,这个人顺时针经过x个人后停下来,当前位置的前一个人出队,然后继续进行,求最后剩下的那个人的可能编号. 思路:由于 ...