概述
Node.js 代码热更新可以带来很多便利之处, 比如可以在服务不停服的情况下更新代码, 修复一个紧急的bug, 更改代码的逻辑. 尤其是在一个长连接服务上, 比如游戏的前端服务器, 重启总是会造成用户大量的断线以及重连, 用户体验非常不好. 但是默认情况下, Node 是不支持热更新的. 原因主要是因为热更新代码时, 需要保持对老的对象的引用, 这样很容易造成内存泄露.
Bearcat 提供了一种热更新代码的方式, 当然也是有一定的限制的, 并不是所有的代码更改都可以热更新.
原理
Bearcat 热更新, 基于 Bearcat 底层强大的 IoC 容器, 通过监听特定的事件, 当有文件更新时, 会动态的在bearcat容器内对有代码更新的POJO, 替换其构造函数的prototype里面的方法. 这样, 因为所有的对象都是共享同一个prototype对象的, 因此当动态更新了 prototype 时, 所有的对象都会热更新, 而且对其里面的私有属性不会产生影响.
这里也就说明了 bearcat 其实热更新的是 prototype 里面的方法, 当你需要更改对象的私有属性时, 这是不支持的.
监听文件夹
Bearcat 默认会监听应用目录下的 hot 文件夹里面的内容, 当里面的内容有更新时, bearcat 就会对更新的文件进行热更新
hot/car.js
var Car = function() {
}
Car.prototype.run = function() {
console.log('run hot car...');
return 'car hot';
}
module.exports = {
id: "car",
func: Car
}
由于更新的是 prototype, 因此更新的文件需要提供更新 bean 的 id 和 func, 来指明需要更新bearcat IoC容器中的哪个bean以及最新的方法定义.
注意点:
- 改变默认监听的文件夹, 可以通过启动时带上 hpath 目录来进行指定
node app hpath=xxx
或者
node app --hpath=xxx
-
目前版本的bearcat是通过 fs.watch 来进行监听文件夹实现的, 因此只支持监听一级目录的文件改变, 比如当你向 hot 文件夹内更新了一个文件夹时, 这样热更新就会出现问题
-
热更新时避免使用全局变量(文件内), 相对路径的require, 因为这些都是耦合依赖的
例子
总结
- 松耦合的系统才能很好的进行热更新, Bearcat 通过 IoC 对系统内的对象进行了解偶, 对象间不直接依赖在一起, 对象们通过bearcat变成一个统一完整的整体, 这也使得对系统内部分对象动态更新成为了可能
####如果本文对你有爱 请:
- 访问 Bearcat, 点击 star
- npm star bearcat
论坛里也有人搞过IOC,js所有类型都是动态的,所以实现容器很容易,不需要反射什么的。 我有一个疑问,框架里好像就是一个容器,并没有什么ioc,谁也没法约束js对象,修改对象的prototype是没有限制的。 我就想程序员喜欢写一堆配置,还是直接修改prototype或者this指针。
@dlutwuwei
哈哈,牛逼的人总是有办法做到的
但是,比如热更新,其实要实现这个就需要一定的限制
比如,之前没用IoC把,你两个文件是直接 require 的,ok 这样子没啥问题
a.js
var a = require('b');
a.run();
b.js
exports.run = function() {
console.log('run');
}
但是这个时候如果你想热更新 b.js ?
这是不可能的,因为 a.js 里面有了 b的引用,require 回来就是一个 module 对象了
相信这样子的代码在node.js中非常的常见与普遍
这个问题其实就需要对代码做些限制,哪些可以写,哪些写了就不是最佳实践了
bearcat 就规范大家写 POJO,就是写简单的js对象,不要使用匿名对象,全局变量这些
而且bearcat把这些POJO统一成为了一个整体,可以很方便的进行管理
不然的话,自己去动态修改prototype或者this指针当然也是可以的
但是这样子你的业务逻辑代码就需要额外的处理这些逻辑,关注哪些对象可以reload,何时更新
最终还是发现还是需要一个容器来统一管理起来使用起来才比较爽