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对象定义的操作,但这个增加是值得的,因为我们大大的提高了代码的可读性。