写点什么

NodeJs 深入浅出之旅:异步 I/O (下)🐂

作者:空城机
  • 2021 年 11 月 10 日
  • 本文字数:1960 字

    阅读完需:约 6 分钟

NodeJs深入浅出之旅:异步I/O (下)🐂

Promise/Deferred 模式 🎱

使用事件的方式是,执行流程需要被预先设定,即使是分支,也需要预先设定,这是由发布/订阅模式的运行机制所决定的。


但是在 Promise/Deferred 模式中,采用先执行异步调用,延迟传递处理的方式


promise/deferred 模式是,根据 promise/A 或者它的增强修改版 promise/A+ 规范 实现的 promise 异步操作的一种实现方式。


在原始的 API 中,一个事件只能处理一个回调。而通过 Deferred 对象,可以对事件加入任意的业务处理逻辑。


比如:

$.get('/api').success(fun1).success(fun2)
复制代码


该模式包括两个部分: promisedeferred

Promise

Promise 对象有以下两个特点(下面这两点也是官方最精华的总结):


(1)对象的状态不受外界影响Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。


(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。这与事件(Event)完全不同,事件的特点是,如果你错过了它,再去监听,是得不到结果的。


阮一峰老师的 Promisehttps://www.bookstack.cn/read/es6/docs-promise.md

模拟 Promise

对于 Promise 对象,只要具备then()方法即可。


then()方法的要求:


  • 接受完成态、错误态的回调方法,在操作完成或者出现错误时,调用对应方法

  • 可选地支持 progress 事件回调作为第三个方法

  • then()方法只接受 function 对象,其他对象将被忽略

  • then()方法继续返回 Promise 对象,以实现链式调用

  • then()方法定义:then(fulfilledHandler, errorHandler, progressHandler)


例子:

class PromiseMade extends EventEmitter{    constructor() {        super();    }    then(fulfilledHandler:Function, errorHandler:Function, progressHandler?:Function) {                this.once('success', fulfilledHandler);        this.once('error', errorHandler);        // this.on('progress', progressHandler);        return this;    }}
class DeferredMade { promise:PromiseMade; state: string; constructor() { this.state = 'pending'; this.promise = new PromiseMade(); } resolve(obj: Function) { this.state = 'fulfilled'; this.promise.emit('success', obj); } reject(err: Function) { this.state = 'rejected'; this.promise.emit('error', err); } progress(data: Function) { this.promise.emit('progress', data); }}
复制代码


此时的DeferredMade类就类似于promise,在调用时可以放在一个函数中模拟使用:

function kwait() {    let deferred = new DeferredMade();    setTimeout(()=>{        deferred.resolve(()=> {            console.log('成功了');        });    }, 3000)    return deferred.promise;}IO.get('/txt', (req, res)=>{    let num = kwait();    num.then(()=>{        console.log('成功了');        res.json({ d: '123' })       },()=>{        console.log('失败了');    })})
复制代码


从这里的代码上,可以看到PromiseDeferred的差别:


  • Deferred主要是作用于内部,用于维护异步模型的状态

  • Promise主要作用于外部,通过then()方法暴露给外部添加自定义逻辑


PromiseDeferred的关系:




适用情况 🏀

发布/订阅模式相比,Promise/Deferred 模式的接口和模型都非常简洁。


将业务中不可变的部分封装在了 Deferred,可变部分交给了 Promise。


对于不同的场景,都需要去封装和改造其 Deferred。


如果场景不常用,封装花费的事件与带来的效率相比并不划算。


  1. Promise 是高级接口,一旦定义,不太容易变化,但对典型问题解决非常有效

  2. 事件是低级接口,可以构成更多复杂的场景




流程控制库 🏈

在 express 当中,还有一类需要手工调用才能持续执行后续调用的方式,这类方法叫做尾触发,常见的是 next


在 express 中,就会有 next 在编写中间件时较为常用。


参考:https://www.jianshu.com/p/6322c32001b7



总结 🎳

在 Node 异步处理过程中,最常使用的就是事件发布订阅和 Promise 了,当然流程控制库的方式也会用大。 对于不同的场景,需要采取最使用的方法,这一点就需要依靠自身判断了,毕竟谁也不知道后续会不会加需求真的对后期需求变更是深恶痛绝

发布于: 39 分钟前阅读数: 4
用户头像

空城机

关注

曾经沧海难为水,只是当时已惘然 2021.03.22 加入

业余作者,在线水文 主要干前端的活,业余会学学python 欢迎各位关注,互相学习,互相进步

评论

发布
暂无评论
NodeJs深入浅出之旅:异步I/O (下)🐂