图片 2

的重要性,谈谈Nestjs的设计思想和使用方法

图片 1

我听说Hooks最近很火。讽刺的是,我想用一些关于 class
组件的有趣故事来开始这篇文章。你觉得如何?

图片 2

最近已经使用过一段时间的nestjs,让人写着有一种java
spring的感觉,nestjs可以使用express的所有中间件,此外完美的支持typescript,与数据库关系映射typeorm配合使用可以快速的编写一个接口网关。本文会介绍一下作为一款企业级的node框架的特点和优点。

本文中这些坑对于你正常使用 React 并不是很重要。
但是假如你想更深入的了解它的运作方式,就会发现实际上它们很有趣。

Web Sockets定义了一种在通过一个单一的 socket
在网络上进行全双工通讯的通道。它不仅仅是传统的 HTTP
通讯的一个增量的提高,尤其对于实时、事件驱动的应用来说是一个飞跃。

从依赖注入(DI)谈起装饰器和注解nestjs的“洋葱模型”nestjs的特点总结

开始第一个。

HTML5 Web Sockets 相对于老的技术有了如此巨大的提升,以致于谷歌的 Ian
Hickson(HTML5 说明书的总编)说:

原文在我的博客中:

首先在我的职业生涯中写过的super(props)自己都记不清:

“将数据的千字节减少到2字节……并将延迟从150ms减少到50ms,这远远超过了边际效应。”事实上,仅这两个因素就足以让谷歌对
Web Sockets 字产生浓厚的兴趣。

一、从依赖注入(DI)谈起(1)、angular中的依赖注入

class Checkbox extends React.Component { constructor(props) { super(props); this.state = { isOn: true }; } // ...}

让我们来看看 HTML5 Web Sockets
是如何通过与传统的解决方案进行比较,从而极大地减少不必要的网络流量和延迟的

从angular1.x开始,实现了依赖注入或者说控制反转的模式,angular1.x中就有controller、service,模块。笔者在早年间写过一段时间的angular1.3,下面举例来说明:

当然,在类字段提案 中建议让我们跳过这个开头:

Polling (轮询), Long-Polling (长轮询), and Streaming (串流)

var myapp=angular.module('myapp',['ui.router']);myapp.controller('test1',function($scope,$timeout){}myapp.controller('test2',function($scope,$state){}
class Checkbox extends React.Component { state = { isOn: true }; // ...}

通常,当一个浏览器访问一个网页时,会向拥有这个页面的服务器发送一个HTTP请求。Web
服务器接受这个请求并返回一个响应。

上面这个就是angular1.3中的一个依赖注入的例子,首先定义了模块名为“myapp”的module,
接着在myapp这个模块中定义controller控制器。将myapp模块的控制权交给了myapp.controller函数。具体的依赖注入的流程图如下所示:

在2015年 React 0.13
增加对普通类的支持时,曾经打算用这样的语法。定义constructor和调用super(props)始终是一个临时的解决方案,可能要等到类字段能够提供在工程学上不那么反人类的替代方案。

在许多情况下——例如,股票价格、新闻报道、机票销售、交通模式、医疗设备读数等等——浏览器渲染页面时,响应可能已经过时,如果你想获得最新的“实时”信息,你可以不断手动刷新该页面,但这显然不是一个很好的解决方案。

myapp这个模块如何定义,由于它的两个控制器决定,此外在控制器中又依赖于$scope、$timeout等服务。这样就实现了依赖注入,或者说控制反转。

不过还是让我们回到前面这个例子,这次只用ES2015的特性:

当前尝试提供实时 Web
应用程序其主要围绕轮询和其他服务器端推送技术,其中最引人注目的是Comet,它会延迟完成
HTTP 响应以将消息传递到客户端。基于 Comet 的推送一般采用 JavaScript
实现并使用长连接或流等连接策略。

(2)、什么是依赖注入

class Checkbox extends React.Component { constructor(props) { super(props); this.state = { isOn: true }; } // ...}

comet:基于 HTTP
长连接的“服务器推”技术。基于这种架构开发的应用中,服务器端会主动以异步的方式向客户端程序推送数据,而不需要客户端显式的发出请求。Comet
架构非常适合事件驱动的 Web
应用,以及对交互性和实时性要求很强的应用,如股票交易行情分析、聊天室和
Web 版在线游戏等。

用一个例子来通俗的讲讲什么是依赖注入。

为什么我们要调用super? 可以调用它吗?
如果必须要调用,不传递prop参数会发生什么? 还有其他参数吗?
接下来我们试一试:

Polling (轮询)

class Cat(){}class Tiger(){}class Zoo(){ constructor(){ this.tiger = new Tiger(); this.cat = new Cat(); }}

在 JavaScript 中,super指的是父类的构造函数。

通过轮询,浏览器定期发送 HTTP
请求并立即接收响应,这项技术是浏览器首次尝试传递实时信息。显然,如果消息传递的确切时间间隔已知,这是一个很好的解决方案,因为可以在服务器上先把需要发送的信息准备好之后在发送给客户端。然而,实时数据通常是不可预测的,这必然造成许多不必要的请求,因此,在低频率消息的情况下,许多连接被不必要地打开和关闭的。

上述的例子中,我们定义Zoo,在其constructor的方法中进行对于Cat和Tiger的实例化,此时如果我们要为Zoo增加一个实例变量,比如去修改Zoo类本身,比如我们现在想为Zoo类增加一个Fish类的实例变量:

重要的是,在调用父类构造函数之前,你不能在构造函数中使用this。
JavaScript 是不会让你这样做的:

Long-Polling (长轮询)

class Fish(){}class Zoo(){ constructor(){ this.tiger = new Tiger(); this.cat = new Cat(); this.fish = new Fish(); }}
class Checkbox extends React.Component { constructor(props) { //这里还不能用 `this` super(props); //现在可以用了 this.state = { isOn: true }; } // ...}

长轮询是让服务器在接收到浏览器所送出 HTTP
请求后,服务器会等待一段时间,若在这段时间里面服务器有新的消息,它就会把最新的消息传回给浏览器,如果等待的时间到了之后也没有新的消息的话,就会送一个回应给浏览器,告知浏览器消息没有更新。

此外如果我们要修改在Zoo中实例化时,传入Tiger和Cat类的变量,也必须在Zoo类上修改。这种反反复复的修改会使得Zoo类并没有通用性,使得Zoo类的功能需要反复测试。

为什么 JavaScript
在使用this之前要先强制执行父构造函数,有一个很好的理由能够解释。
先看下面这个类的结构:

虽然轮询可以减少产生原本轮询造成网络带宽浪费的情况,但是,如果在资料更新频繁的状况下,长时间轮询不传统比传统的轮询有效率,而且有时候资料量很大时,会造成连续的轮询不断产生,反而会更糟糕。

我们设想将实例化的过程以参数的形式传递给Zoo类:

class Person { constructor(name) { this.name = name; }}class PolitePerson extends Person { constructor(name) { this.greetColleagues(); //这行代码是无效的,后面告诉你为什么 super(name); } greetColleagues() { alert('Good morning folks!'); }}

串流

class Zoo(){ constructor(options){ this.options = options; }}var zoo = new Zoo({ tiger: new Tiger(), cat: new Cat(), fish: new Fish()})

如果允许在调用super之前使用this的话。一段时间后,我们可能会修改greetColleagues,并在提示消息中添加Person的name:

串流 (streaming) 是让服务器在接收到浏览器所送出的 HTTP
请求后,立即产生一个回应浏览器的连接,并且让这个连接持续一段时间不要中断,而服务器在这段时间内如果有新的消息,就可以透过这个连接将消息马上传送给浏览器。

我们将实力化的过程放入参数中,传入给Zoo的构造函数,这样我们就不用在Zoo类中反复的去修改代码。这是一个简单的介绍依赖注入的例子,更为完全使用依赖注入的可以为Zoo类增加静态方法和静态属性:

 greetColleagues() { alert('Good morning folks!'); alert('My name is ' + this.name + ', nice to meet you!'); }

然而,由于流仍然封装在 HTTP
中,介入的防火墙和代理服务器可能会选择缓冲响应,从而增加消息传递的延迟。因此,如果检测到缓冲代理服务器,流式Comet解决方案将退回到长轮询。或者,可以使用TLS
(SSL)连接来防止响应被缓冲,但是这种情况下创建和销毁每一个连接将消耗更多的可用的服务器资源。

class Zoo(){ static animals = []; constructor(options){ this.options = options; this.init(); } init(){ let _this = this; animals.forEach(function(item){ item.call(_this,options); }) } static use(module){ animals.push([...module]) }}Zoo.use[Cat,Tiger,Fish];var zoo = new Zoo(options);

但是我们忘记了super()在设置this.name之前先调用了this.greetColleagues()。
所以此时this.name还没有定义!
如你所见,像这样的代码很难想到问题出在哪里。

TLS:安全传输层协议用于在两个通信应用程序之间提供保密性和数据完整性。
该协议由两层组成: TLS 记录协议和 TLS 握手协议。

SSL:SSL(Secure Sockets Layer
安全套接层),及其继任者传输层安全是为网络通信提供安全及数据完整性的一种安全协议。TLS与SSL在传输层对网络连接进行加密。

上述我们用Zoo的静态方法use往Zoo类中注入Cat、Tiger、Fish模块,将Zoo的具体实现移交给了Cat和Tiger和Fish模块,以及构造函数中传入的options参数。

为了避免这类陷阱,JavaScript
强制要求:如果想在构造函数中使用this,你必须首先调用super

先让父类做完自己的事! 这种限制同样也适用于被定义为类的 React 组件:

最后,所有这些提供实时数据的方法都会引入 HTTP
请求和响应报头,这些报头包含大量额外的、不必要的报头数据,并会带来延迟。

(3)、nestjs中的依赖注入

 constructor(props) { super(props); // ✅ 在这里可以用 `this` this.state = { isOn: true }; }

最重要的是,全双工连接需要的不仅仅是从服务器到客户端的下行连接。为了在半双工HTTP上模拟全双工通信,当今的许多解决方案使用两个连接:一个用于下行,一个用于上行,这两个连接的维护和协调在资源消耗方面引入了大量开销,并增加了许多复杂性。

在nestjs中也参考了angular中的依赖注入的思想,也是用module、controller和service。

这里又给我们留下了另一个问题:为什么要传props参数?

简单地说,HTTP
不是为实时、全双工通信而设计的,可以在下面的图中看到,该图展示了构建
Comet Web 应用(在半双工的 HTTP 上使用订阅模式实时获取后端数据)的复杂性。

@Module({ imports:[otherModule], providers:[SaveService], controllers:[SaveController,SaveExtroController]})export class SaveModule {}

你可能认为将props传给super是必要的,这可以使React.Component的构造函数可以初始化this.props:

当试图将 Comet 的解决方案扩充系统的规模时会变得更糟。在 HTTP
模拟全双工的浏览器通讯易出错、复杂而且复杂度无法降低。尽管最终用户可能正在体验类似于实时
Web应用程序的服务,但这种 “实时”
体验的代价高得惊人。这个代价是,付出额外的延迟,不必要的网络流量和
CPU性能的影响上。

上面就是nestjs中如何定一个module,在imports属性中可以注入其他模块,在prividers注入相应的在控制器中需要用到的service,在控制器中注入需要的controller。

// Inside Reactclass Component { constructor(props) { this.props = props; // ... }}

HTML5 WebSocket 通訊协议

二、装饰器和注解

这与正确答案很接近了 —— 实际上它就是这么做的。

在 HTML5 规范的通信部分中定义,HTML5 Web Sockets
代表了全双工的网络交互的下一个演变 —— 一个全双工、双向的通信通道,通过
Web 上的单个套接字进行操作。

在nestjs中,完美的拥抱了typescript,特别是大量的使用装饰器和注解,对于装饰器和注解的理解可以参考我的这篇文章:Typescript中的装饰器和注解。我们来看使用了装饰器和注解后,在nestjs中编写业务代码有多么的简洁:

但是不知道为什么,即便是你调用super时没有传递props参数,仍然可以在render和其他方法中访问this.props。

HTML5 Web Sockets 提供了一个真正的标准,可以使用它来构建可扩展的实时 Web
应用程序。此外,由于它提供了浏览器本地的套接字,因此避免了 Comet
解决方案容易出现的许多问题。 Web Socket s移除了开销大幅度减轻了复杂度。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

标签:, , , , , , , , , ,

相关文章

网站地图xml地图