async and await
为了帮助你了解一下历史的进程,我画了如下图来解释我们为啥要 async 和 await

简介
async 和 await 是为了简化 Promise 模式而被提出来的一种解决方案,所以为了学习 async 和 await 我们需要先明白 Promise 模式是啥。
Promise 模式的提出是为了替代 JS 中本身的回调语法,那么为啥要替代回调语法呢?我们知道,JS 一般的实现都是单线程的,所以我们都使用回调函数来进行操作的同步。但是,回调函数写起来实在是太丑了,一段使用回调函数的代码可能是这样的(出自http://callbackhell.com/):

因为写起来太难看了,而且理解起来也很不方便,所以人们就开始想办法解决回调函数的问题。此时,Promise 模式被提出来了,要知道 Promise 模式是怎么替代回调函数的,参考如下代码:
最基本的回调函数方式
1 | var fs = require("fs") |
改写为 Promise 模式
1 | var fs = require("fs") |
Promise 模式
Promise 类在 nodejs 中已经为我们构建好了(主流浏览器应该也都实现了这个类),所以我们可以直接使用。Promise 的构造方法入参是一个方法,这个方法传入两个参数:resolve 和 reject。根据约定,当程序执行正常,方法 resolve 被执行;当程序出现异常,方法 reject 被执行。方法的执行条件已经定义完毕,下面就是方法体的定义了。方法readFile('input.txt')返回一个 Promise 对象,我们调用其 then 方法,这个方法传入两个方法。根据约定,第一个方法是为 resolve 方法的方法体,第二个方法是为 reject 方法的方法体。
也就是说,then 方法中的两个参数分别就是和 Promise 中传入的方法的两个参数相对应的。上面的 resolve 方法执行了,执行的就是 then 方法中的 resolve 方法方法体(参数也被正确的传递);上面的 reject 执行了,执行的就是下面 reject 方法方法体。
async and await
我们发现,Promise 虽然在执行时避免了回调地狱,但是写这个 then 方法还是挺丑的,我们想要去掉这个 then。因此,async 和 await 就出现了,它们的目的是___当调用___Promise 对象的方法时候,能够简化操作。我们还是使用上面例子中的 Promise 对象的定义方式,而使用 async 和 await 来替代之前的 Promise 方法的执行方式,代码如下:
1 | var fs = require("fs") |
我们定义了一个 async 方法,在方法内使用 await 关键字修饰了一个 Promise 对象,这个修饰符将会把 resolve 对象执行时的入参返回,我们用 data 变量接受这个参数。仔细想想,我们的核心目的不就是接受到 resolve 方法和 reject 方法的参数吗?因为方法体其实都是我们自己定义的,如此一来拿到了 resolve 方法的入参,我们就可以用这个参数执行我们想要的操作了;同样的,根据约定,在 async 方法中 reject 方法一旦执行就会触发异常,所以我们用 try catch 包裹了代码快,catch 的参数就是 reject 方法执行时候的入参。
仔细观察上面的代码,这样一来代码就非常的整洁且容易理解了。虽然我们增加了一个 Promise 对象定义的操作,但这个增加是值得的,因为我们大大的提高了代码的可读性。