异步编程从早期的回调,事件发布\订阅模式到ES6的承诺,发电机在到ES2017中异步,看似风格迥异,但是还是有一条暗线将它们串联在一起的,就是希望将异步编程的代码表达尽量地贴合自然语言的线性思维。
以这条暗线将上述几种解决方案连在一起,就可以更好地理解异步编程的原理,魅力。
├──事件发布\订阅模式& lt;=回调
├──承诺& lt;=事件发布\订阅模式
├──异步等待& lt;=承诺,发电机
这个模式本质上就是回调函数的事件化。它本身并无同步,异步调用的问题,我们只是使用它来实现事件与回调函数之间的关联。比较典型的有NodeJS的事件模块
const {EventEmitter}=要求(“事件”) const eventEmitter=new eventEmitter ()//订阅 eventEmitter。(“事件”,函数(味精){ 控制台。日志(“事件”,味精) })//发布 eventEmitter。发出(“事件”,“Hello world”)
那么这种模式是如何与回调关联的呢?我们可以利用Javascript简单实现EventEmitter,答案就显而易见了。
类usrEventEmitter { 构造函数(){ 这一点。听众={} }//订阅,回调为每个事件的侦听器 (eventName,回调){ 如果(! this.listeners [eventName])。听众[eventName]=[] this.listeners [eventName] .push(回调) }//发布 发出(eventName params) { this.listeners [eventName]。forEach(回调=比;{ 回调(params) }) }//注销 (eventName,回调){ const休息=this.listeners [eventName]。fitler (elem=比;elem !==回调) 这一点。听众[eventName]=休息 }//订阅一次 一次(eventName,回调){ 常量处理程序=function () { 回调() 这一点。(eventName处理程序) } 这一点。(eventName处理程序) } }
上述实现忽略了很多细节,例如异常处理,多参数传递等。只是为了展示事件订阅\发布模式。
很明显的看的出,我们使用这种设计模式对异步编程做了逻辑上的分离,将其语义化为
//一些事件可能会被触发 eventEmitter.on//当它发生的时候,要这样处理 eventEmitter.emit
也就是说,我们将最初的调变成了事件监听器,从而优雅地解决异步编程。
使用事件发布\订阅模式时,需要我们事先严谨地设置目标,也就是上面所说的,必须要缜密地设定好有哪些事件会发生。这与我们语言的线性思维很违和。那么有没有一种方式可以解决这个问题,社区产出了承诺。
const承诺=新的承诺(函数(解决,拒绝){
尝试{
setTimeout(()=比;{
解决(“hello world”)
}, 500)
}捕捉(错误){
拒绝(错误)
}
})
//语义就变为先发生一些异步行为,然后我们应该这么处理 的承诺。然后(味精=比;console.log(味精))。抓住(错误=比;控制台。日志(“犯错”,错误))
那么这种承诺与事件发布\订阅模式有什么联系呢?我们可以利用EventEmitter来实现承诺,这样可能会对你有所启发。
我们可以将视承诺为一个EventEmitter,它包含了{状态:“等待”}来描述当前的状态,同时侦听它的变化
-
<李>当成功时{状态:“满足”},要做些什么>
const {EventEmitter}=要求(“事件”)
类usrPromise延伸EventEmitter {//构造时候执行
构造函数(执行者){
super ()//发布
const解决=(值)=比;这一点。发出(“解决”,值)
const拒绝=(原因)=比;这一点。发出(“拒绝”,原因)
如果(执行者){//模拟事件循环,注此处利用Macrotask来模拟Microtask
setTimeout(()=比;遗嘱执行人(解决,拒绝))
}
}
然后(resolveHandler rejectHandler) {
const nextPromise=new usrPromise ()//订阅解决事件
如果(resolveHandler) {
const解决=(数据)=比;{
const结果=resolveHandler(数据)
nextPromise。发出(‘解决’,结果)
}
这一点。(“解决”,解决)
}//订阅拒绝事件
如果(rejectHandler) {
const拒绝=(数据)=比;{
const结果=rejectHandler(数据)
nextPromise。发出(“拒绝”,结果)
}
这一点。(“拒绝”,拒绝)
其他}{
这一点。(“拒绝”,(数据)=比;{
的承诺。发出(“拒绝”,数据)
})
}
返回nextPromise
}
抓住(处理器){
这一点。(“拒绝”,处理程序)
}
}