In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
This article mainly introduces the relevant knowledge of "what is the module mechanism of Nestjs framework in Node.js". The editor shows you the operation process through an actual case, the operation method is simple and fast, and it is practical. I hope this article "what is the module mechanism of Nestjs framework in Node.js" can help you solve the problem.
Nest provides a module mechanism, which completes dependency injection by defining provider, import, export, and provider constructors in the module decorator, and organizes the development of the entire application through the module tree. There is no problem with directly mastering an application according to the agreement of the framework itself. However, it seems to me that there is a lack of a clearer and systematic understanding of the framework's claimed dependency injection, control inversion, modules, providers, metadata, related decorators, and so on.
Why do you need control reversal?
What is dependency injection?
What did the decorator do?
What is the implementation principle of provider (providers), import (imports) and export (exports) in the module (@ Module)?
Seems to be able to understand, can understand, but let me make it clear from the beginning, I do not know. So after some exploration, there is this article. From now on, let's start anew and get into the text.
1 two stages
1.1 Express 、 Koa
The development of a language and its technology community must gradually enrich its functions from the bottom up, just like the process of roots growing into branches and then full of leaves. In the early days, Nodejs introduced basic Web service frameworks such as Express and Koa. Be able to provide a very basic service capability. Based on this framework, a large number of middleware and plug-ins began to be born in the community to provide more rich services for the framework. We need to organize our own application dependence, build application scaffolding, flexible and tedious, but also have a certain amount of work.
In the later stage, some frameworks with more efficient production and more unified rules were born, which opened a new stage.
1.2 EggJs 、 Nestjs
In order to adapt to the application of rapid production, unified specification and out-of-the-box use, EggJs, NestJs, Midway and other frameworks have been developed. This kind of framework abstracts the implementation of an application into a universal and extensible process by implementing the underlying life cycle. We only need to follow the configuration provided by the framework to implement the application more easily. The framework implements the process control of the program, and we just need to assemble our parts in the right place, which looks more like an assembly line, each process is clearly segmented and saves a lot of implementation costs.
1.3 Summary
The above two stages are just a groundwork, we can roughly understand that the upgrade of the framework is to improve production efficiency, and to achieve the upgrade of the framework, some design ideas and patterns will be introduced, and the concepts of control inversion, dependency injection and metaprogramming appear in Nest. Let's talk about it next.
2 control inversion and dependency injection
2.1 dependency injection
An application is actually a lot of abstract classes that implement all the functions of the application by calling each other. With the increase of application code and functional complexity, the project will become more and more difficult to maintain, because there are more and more classes, and the relationship between them becomes more and more complex.
For example, if we use Koa to develop our application, Koa itself mainly implements a set of basic Web service capabilities. In the process of implementing the application, we will define many classes. The instantiation and interdependence of these classes will be freely organized and controlled by us in the code logic. The instantiation of each class is manually new by us, and we can control whether a class is instantiated only once and then shared, or each time. The following class B depends on A, which is instantiated every time B is instantiated, so for each instance B, An is an unshared instance.
Class A {} / / Bclass B {contructor () {this.a = new A ();}}
The following C is the acquired external instance, so multiple C instances are shared app.an instances.
Class A {} / / Cconst app = {}; app.a = new A (); class C {contructor () {this.a = app.a;}}
The following D is passed through the constructor parameter, you can pass in a non-shared instance at a time, you can also pass in the shared app.an instance (D and F shared app.a), and since it is now a parameter, I can also pass in an X instance.
Class A {} class X {} / / Dconst app = {}; app.a = new A (); class D {contructor (a) {this.a = a;}} class F {contructor (a) {this.a = a;}} new D (app.a) new F (app.a) new D (new X ())
This way is dependency injection, which injects the A that B depends on into B by passing a value. Injecting (passing values) through the constructor is just one way to implement it, and you can also implement the set method call to pass in, or any other way, as long as you can pass an external dependency to the inside. It's as simple as that.
Class A {} / / Dclass D {setDep (a) {this.a = a;}} const d = new D () d.setDep (new A ())
2.2 All in dependency injection?
As the iteration goes on, it appears that the B dependency will change according to different preconditions. For example, the precondition one this.a needs to pass in an instance of A, and the antecedent condition two this.a requires an instance of X. At this point, we will begin to do the actual abstraction. We will transform it into the dependency injection method like D above.
In the initial stage, when we implement the application, when we meet the needs at that time, we will achieve the writing of class B and C, which is not a problem in itself. after several years of iteration, the project will not necessarily move this part of the code. If we think about what to expand later, it will affect the efficiency of development, and it may not be useful. So most of the time, we encounter scenarios that need to be abstracted, and then make abstract modifications to some of the code.
/ / class B {contructor () {this.a = new A ();}} new B () / / class D {contructor (a) {this.a = a;}} new D (new A ()) new D (new X ())
According to the current development model, three types of CBD will exist, B and C have a certain chance to develop into D, each upgrade D abstract process, we will need to ReFactor the code, which is a kind of implementation cost.
The purpose of this example is to illustrate that in a development mode without any constraints or regulations. We are free to write code to achieve dependency control between various classes. In a completely open environment, it is very free, this is a primitive era of slash-and-burn cultivation. Because there is no fixed code development model and no highest action plan, with the intervention of different developers or the difference of writing code in different time periods of the same developer, the dependency will become very unclear in the process of code growth, and the shared instance may be instantiated many times, wasting memory. It is difficult to see a complete dependency structure from the code, and the code can become very difficult to maintain.
Then every class we define is written as D in the way of dependency injection, so the abstract process of C and B is advanced, so it is more convenient to expand later and reduce the cost of transformation. So call this All in dependency injection, which means that all our dependencies are implemented through dependency injection.
But the cost of implementation in the early stage becomes higher, it is difficult to achieve unity in teamwork and adhere to it, and may eventually fail, which can also be defined as a kind of over-design, because the additional implementation cost does not necessarily bring benefits.
2.3 Control reversal
Now that we have agreed on a unified way to use dependency injection, can we implement an underlying controller and agree on a dependency configuration rule through the underlying encapsulation of the framework? the controller controls the instantiation process and dependency sharing according to our defined dependency configuration to help us achieve class management. Such a design pattern is called control inversion.
Control reversal may be difficult to understand when you hear it for the first time. What does control mean? Reversed what?
The guess is that developers used such frameworks from the beginning and did not experience the last "Express and Koa era" and lacked the beating of the old society. Coupled with this reversal of the use of words, in the program appears to be very abstract, difficult to read literal meaning.
In the previous article, we are talking about the implementation of Koa applications, all the classes are completely under our free control, so it can be regarded as a conventional way of program control, which is called control forward. While we use Nest, which implements a set of controllers at the bottom, we only need to write the configuration code according to the agreement in the actual development process, and the framework program will help us manage the dependency injection of the class, so it is called control inversion.
In essence, the implementation process of the program is handed over to the framework program to be managed uniformly, and the control is handed over from the developer to the framework program.
Control positive turn: developers purely manual control program
Control reversal: frame program control
To take a realistic example, a person is supposed to drive to work by himself, and his goal is to get to the company. It drives its own car and controls its own route. If you hand over the control of the car, that is, to catch the bus, he only needs to choose a corresponding bus to get to the company. In terms of control alone, people are liberated, just remember which bus to take, the chances of making mistakes are smaller, and people are much more relaxed. The bus system is the controller, and the bus route is the agreed configuration.
Through the actual comparison above, I think I can understand the control reversal a little bit.
2.4 Summary
From Koa to Nest, from front-end JQuery to Vue React. In fact, they are all encapsulated step by step through the framework to solve the problem of inefficiency in the last era.
The above Koa application development, through a very primitive way to control dependencies and instantiation, similar to the front-end JQuery operation dom, this very primitive way to call it control forward, and Vue React is like Nest provides a layer of program controller, they can all be called control inversion. This is also a personal understanding, if there is a problem, expect the god to point out.
Let's talk about the module @ Module in Nest, which is needed as a medium for dependency injection and control inversion.
Module of 3 Nestjs (@ Module)
Nestjs implements control inversion, agreeing on the imports, exports, and providers management providers of the configuration module (@ module), that is, the dependency injection of the class.
Providers can be understood to register and instantiate classes in the current module, and the following An and B are instantiated in the current module. If B references An in the constructor, it is the An instance of the current ModuleD referenced.
Import {Module} from'@ nestjs/common';import {ModuleX} from'. / moduleX';import {A} from'. / imports: [ModuleX], providers: [ModuleX], exports: [A]}) export class ModuleD {} / / Bclass B {constructor (aRana) {this.a = a;}}
Exports refers to the class instantiated in the providers in the current module as a class that can be shared by external modules. For example, when class C of ModuleF is instantiated, you want to inject class An instance of ModuleD directly. Just set export (exports) An in ModuleD and import ModuleD through imports in ModuleF.
According to the following writing, the control inversion program will automatically scan for dependencies. First, see if there is provider An in the providers of your module. If not, find out if there is an An instance in the imported ModuleD, and then inject the An instance of ModuleD into the C instance.
Import {Module} from'@ nestjs/common';import {ModuleD} from'. / moduleD';import {C} from'. / imports: [ModuleD], providers: [C],}) export class ModuleF {} / / Cclass C {constructor (aRana) {this.a = a;}}
So if you want the external module to use the class instance of the current module, you must first define the instantiated class in the providers of the current module, and then define and export this class, otherwise an error will be reported.
/ / correct @ Module ({providers: [A], exports: [A]}) / / error @ Module ({providers: [], exports: [A]}) later supplement
The process of looking for an instance of the module looks back, and it is really a little unclear. The core point is that the classes in providers will be instantiated, then the provider will be instantiated, only the classes in providers will be instantiated in the module, and the export and import is just an organizational relationship configuration. The module will give priority to using its own provider. If not, find out whether the imported module has a corresponding provider.
Here I would like to mention the knowledge of ts.
Export class C {constructor (private a: a) {}}
Because TypeScript supports the implicit automatic definition of constructor parameters (private, protected, public, readonly) as the class attribute (Parameter Property), there is no need to use this.a = a. This is the way it is written in Nest.
4 Nest metaprogramming
The concept of metaprogramming is embodied in the Nest framework, and its control inversion and decorator are the realization of metaprogramming. It can be understood that the essence of metaprogramming is still programming, but there are some abstract programs in the middle. This abstract program can recognize metadata (such as object data in @ Module). It is actually an extensibility that can deal with other programs as data. When we are writing such an abstract program, we are in metaprogramming.
4.1 metadata
Metadata is also often mentioned in Nest documents, and the concept of metadata will be difficult to understand when you see it for the first time. You need to get used to understanding it with contact time, so you don't have to struggle too much.
The definition of metadata is: the data that describes the data, mainly the information that describes the attributes of the data, and can also be understood as the data that describes the program.
Exports, providers, imports, and controllers configured in @ Module in Nest are all metadata, because it is data used to describe program relationships, which is not the actual data displayed to the end user, but read and identified by the framework program.
4.2 Nest decorator
If you look at the source code of the decorator in Nest, you will find that almost every decorator itself simply defines a metadata through reflect-metadata.
@ Injectable decorator
Export function Injectable (options?: InjectableOptions): ClassDecorator {return (target: object) = > {Reflect.defineMetadata (INJECTABLE_WATERMARK, true, target); Reflect.defineMetadata (SCOPE_OPTIONS_METADATA, options, target);};}
There is the concept of reflection, and reflection is easy to understand. Take @ Module decorator as an example to define metadata providers. Only classes are passed into the providers array. When the program is actually running, the classes in providers are automatically instantiated as providers by the framework program, and do not need to be instantiated and dependency injected as shown by the developer. The class becomes a provider only after it is instantiated in the module. Classes in providers are reflected as providers, and inversion of control is the reflection technology utilized.
Another example is ORM (object-relational mapping) in the database. Using ORM, you only need to define table fields, and the ORM library automatically converts the object data into SQL statements.
Const data = TableModel.build (); data.time = 1bot data.browser = 'chrome'; data.save (); / / SQL: INSERT INTO tableName (time,browser) [{"time": 1, "browser": "chrome"}]
ORM library is the use of reflection technology, so that users only need to pay attention to the field data itself, the object is reflected by the ORM library into SQL execution statements, developers only need to pay attention to the data fields, and do not need to write SQL.
4.3 reflect-metadata
Reflect-metadata is a reflection library that Nest uses to manage metadata. Reflect-metadata uses WeakMap to create a global single instance to set and get the metadata of the decorated object (class, method, and so on) through the set and get methods.
/ / just take a look at var _ WeakMap =! usePolyfill & & typeof WeakMap = = "function"? WeakMap: CreateWeakMapPolyfill (); var Metadata = new _ WeakMap (); function defineMetadata () {OrdinaryDefineOwnMetadata () {GetOrCreateMetadataMap () {var targetMetadata = Metadata.get (O); if (IsUndefined (targetMetadata)) {if (! Create) return undefined; targetMetadata = new _ Map (); Metadata.set (O, targetMetadata) } var metadataMap = targetMetadata.get (P); if (IsUndefined (metadataMap)) {if (! Create) return undefined; metadataMap = new _ Map (); targetMetadata.set (P, metadataMap);} return metadataMap;}
Reflect-metadata stores the metadata of the decorated person in the global singleton object and manages it uniformly. Reflect-metadata does not implement specific reflection, but provides a library of tools to assist reflection implementation.
This is the end of the content about "what is the module mechanism of the Nestjs framework in Node.js". Thank you for reading. If you want to know more about the industry, you can follow the industry information channel. The editor will update different knowledge points for you every day.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.