Maple's Blog.

Node 和观察者设计模式

字数统计: 938阅读时长: 3 min
2018/08/27

观察者设计模式

观察者模式(有时又被称为模型-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。

总的来说,例如 Node 的事件机制。除非是一个不包含异步的程序(如果没有异步逻辑,那这个程序在执行结束前都不会有事件循环),否则一般程序在拥有带监听的 IO 事件(或者是网络套接字)的观察者时,就会通过线程层(libuv)不断的是轮询这些事件有没有完成。而系统在完成 IO 之后,将消息包装成事件发送给 IO 观察者(实质上是轮询)。而观察者在获得事件之后,检查这个事件的监听者(实质上就是 callback 函数),将时间调用给 callback 函数,实现 JS 的运行。

一个比较小的细节。一个 Node 程序,如果不包含异步操作,则在函数全部完成之后退出程序。而如果包含一个异步操作,哪怕这个操作并没有 callback 函数,他也会在异步函数完成之后才退出函数。这也说明了 Node 的运行机制,实质上并非是简单的运行 JavaScript。而是通过检查 libuv 里的观察者,一旦有观察者存在,就不会退出程序,继续轮询着这些观察者,直至最后一个观察者退出。而观察者一旦接受事件,则会触发事件机制,调用监听这些事件的 callback,从而调用了 Javascript 的同步函数。

这是阿里的一个面试官问我的问题:什么是观察者设计模式?当时完全懵逼因为之前都没听说过这个名词。回去查了下发现其实也没有这么不好理解。

但是半夜结合实际想了想,反而对 Node 的异步机制有了进一步的了解。

首先是 Node 做的事情并不是单纯的让 js 运行起来。他创建了一个轮询的队列。在函数运行初,js 代码将一个个观察者加入到这个队列之中。然后运行完他本身的 JS 代码(除了 callback) 里面的。

然后这个队列开始不停的轮询,检查这些观察者所观察的系统级的 IO 操作有没有完成。一旦某个 IO 完成,观察者获得事件之后,再运行其中的 callback 函数(实质我估计是把同个循环的可以的运行的 callback 都放到一个 list 里面再运行 js。这样不会保证同时调起多个 js)。如果这些函数里还有新的观察者,则把这些观察者重新加入到 list 中。等这个循环所有的 js 都运行完成之后。结束并重新对观察者队列进行轮询。直到所有的观察者都结束之后,退出程序。

这也是 Node 异步和同步的真正原因:

  1. callback 的函数实质上并不会在这一次被运行,而是等 IO 完成后由观察者重新唤起。
  2. 异步逻辑实质上只是生成观察者并把它放到队列中。
  3. try catch 不能抓取异步操作也是这个原因。因为这其实是两次不同的 js 解释运行。
CATALOG
  1. 1. 观察者设计模式