tit*_*300 4 javascript node.js winston
出于个人学习的目的,我试图了解Winston的软件包设计结构以及每个模块背后的目的,但我无法理解这一点.
在Winstons包中,logger.js模块中有核心Logger类,它实现了记录器的主要功能,并提供了一些公共方法,例如方法.它还实现了内部使用的转换流方法.logger.log
然后在create-logger.js模块中有一个派生类,DerivedLogger它扩展了Logger类,它的唯一目的似乎是为loggers原型添加优化级别方法.DerivedLogger然后将该类实例化并导出到模块底部的工厂函数中.
我的问题是,为什么DerivedLogger需要上课?如果将这些级别方法添加到Logger类原型本身然后让工厂函数Logger直接实例化该类,那么性能会有什么不同吗?我能想到的唯一原因是,这个DerivedLogger类可能只是为了模块化目的而添加的吗?有人可以帮我理解原因吗?
谢谢!
这个非常有趣,多亏了指出来!
简而言之:它与代码结构无关,它是一种性能优化.评论说明了这一点:
创建一个新的类派生记录器,其级别可以附加到原型.这是一个众所周知的V8优化,可以提高原型功能的性能.
就个人而言,我认为这需要引用(我不会在代码审查中接受它).幸运的是,我认为我找到了作者所说的"优化":
Mathias(一位在V8上工作的Google工程师)的这篇文章讨论了如何通过正确使用来加速JavaScript执行prototype.这篇文章有很多细节,如果你正在学习,真的值得一读.
Winston中的优化归结为:
该
getAttribute()方法见于Element.prototype.这意味着每次调用时anchor.getAttribute(),JavaScript引擎都需要......
- 检查
getAttribute锚对象本身不是,- 检查直接原型是
HTMLAnchorElement.prototype,- 断言没有
getAttribute,- 检查下一个原型是
HTMLElement.prototype,- 声称没有
getAttribute那里,- 最终检查下一个原型是
Element.prototype,- 而且
getAttribute那里有.总共有7张支票!由于这种代码在Web上很常见,因此引擎会应用技巧来减少原型上属性加载所需的检查次数.
这大致适用于温斯顿,如下:
prototype所述类别的-objectprototype被叫方法连接到.prototypeprototype-chain转到下一个类并查看那里prototype达到-chain 的结尾(并抛出错误).通过_setupLevels()在构造函数中运行,level-methods直接附加到特定记录器实现实例的原型.这意味着,类层次结构可以尽量增大:在prototypeα链查询只需要1步找对方法
这是另一个(简化)示例:
class A {
constructor() {
this.setup();
}
testInherit() {
console.log("Inherited method called");
}
setup() {
this["testDirect"] = () => console.log("Directly attached method called");
}
}
class B extends A {
constructor() {
super();
}
}
const test = new B();
test.testInherit();
test.testDirect();
Run Code Online (Sandbox Code Playgroud)
如果我们在test实例化之后设置断点,我们会看到以下内容:
正如您所看到的,testDirect-method直接附加到test,而testInherit多个级别下降.
我个人认为这是不好的做法:
不要乱用原型
至于模块化:对于所有扩展都有明确的基类,有一些东西可以说.
使用比JavaScript更严格的语言,这样的类可以提供仅用于扩展的特定方法,这些方法对于消费者来说是公共API隐藏的.然而,在这个特定的情况下,Logger本来可以没问题.