Nodejs实现异步编程优化方案之-Promise
一、前言:为什么要优化
我们可以思考这样一个场景:
产品经理:突然有一个需求,有300个文件需要按照顺序读取,麻烦用回调函数实现。 我:好的,等等,多少?我难道要嵌套300层,不行可读性太差了,谁能维护的了,想想其他办法。
其实,上面的场景只是一个极端的案例用来说明回调函数实现异步编程的局限性,即有多个异步函数需要顺序执行时,产生的一种异步函数嵌套的情况,我们就称之为回调地狱。
官网是这么描述的:
(感觉官网描述的也不是特别定义化,同样是通过栗子来说明的)
那为了解决这个问题,Promise异步编程解决方案就应运而生了。
二、Promise解决方案
首先看一下Promise是怎么实现异步操作的:
我们先来看官网是怎么介绍Promise的
头皮发麻?
让我们来梳理下重点:
1.Promise 是一个对象,通过new关键字使用,传入一个函数(执行器),函数会被立即执行,并且返回一个Promise实例。
2.一个Promise有三种状态:
Pending:初始状态
Fulfilled:操作成功状态
Rejected: 操作失败状态
等等,什么叫操作?
其实,所谓操作就是指在传入的函数中,调用异步函数的行为。
状态之间是怎么变化的?
Promise提供了两个方法,可以返回操作成功、操作失败的结果:
reject 可以把pending状态 变成 rejected状态;
resolve 可以把pending状态 变成 fulfilled状态;
那我们如何拿到这个结果,上代码:
既然Promise给我们返回了一个实例对象,那就可以通过这个实例对象获取操作结果。实例对象提供了两个方法,then方法可以获得操作成功的返回值,catch方法可以获得操作失败的返回值。
(还是以回调函数的形式,可见回调函数多么多么重要!!!)
整体实现如下:
小结:Promise 中文翻译为“承诺”,也可以这么理解,它承诺给我们完成一件事情(异步操作),并且一定会返回一个结果(两种状态)。
那如何实现上面产品经理的需求呢?
我们可以定义一个通用函数,这个函数返回的是一个Promise实例,然后在需要的地方进行调用,上代码:
实现是实现了,但这不还是要写300个Promise实例?
怎么办,救命!!!
别急,Promise早就想到了这个问题,因此它提供了一种链式调用的功能。
什么叫链式调用?
依然很懵逼,别着急,大致意思就是说我们在then方法中,除了可以拿到成功的返回值之外,还可以调用一个新的Promise实例,然后在下一个then方法中拿到对应的返回值。
上代码:
哈哈哈,看起来就比上面的方式好很多了!
三、Async/Await
虽然Promise提供了链式调用的方式,极大简化了代码,那还有没有更优雅的方式呢?
既然同步编程非常可读,那我们能不能通过同步编程的方式实现异步操作呢?
其实,Nodejs跟我们想得一样,在ES6中果然就给我们提供了这样一种解决方案,上代码:
这跟Promise有啥区别?
当你细品的时候,就会发现在function关键字前面多了一个async关键字,这是个啥?
老规矩,先看官网:
其实,async只是在原有Promise的基础上做了一些简化,不用再通过链式调用获取上一个Promise的返回值了。
通过async关键字,可以声明一个异步函数,这个函数就会返回一个Promise实例。
通过await关键字,就可以暂停后面异步函数的执行,等到异步函数返回结果后,再向下执行。
(是不是有点同步的感觉了)
那有的同学就会问了,你这样不就又回到同步的写法了嘛?兜了这么一大圈子,玩呢。
其实不然,这就牵涉到了Nodejs的异步编程最核心的事件循环机制,我们将在后面详细展开。
总之就是,通过这种方式,就可以通过同步编码的方式,实现异步编程。
四、结尾彩蛋
3秒钟回忆一下我们是如何通过Promise实现依次读取三个文件的内容的,
我们是先定义了一个myReadFile方法,该方法返回一个Promise实例,Promise实例中再调用fs.readFile异步方法,fs.readFile方法再通过回调函数返回最终的值。
啊这......
有没有更好的办法呢,我要是可以直接调用一个Promise的异步方法就好了。
哈哈,先别喷,贴心的Nodejs模块早就给我们准备好了,终极武器:Promisify。
(一看...fy,喜欢英语的小伙伴都知道,一般是“把...化”的意思。也就是“把...Promise化”,放在Nodejs中,就是把一个异步操作Promise化)。
上代码:
通过util库提供的promisify方法,我们可以把任意一个异步操作直接变成一个promise,省略了自己封装Promise、回调返回结果的过程。
好了,那新的问题来了,当不同的异步操作发生时,执行顺序究竟是怎样的?
下一期我们将对这个问题进行深入探讨。
转载自:https://juejin.cn/post/7209162467927785529