想要清楚地了解 NodeJS 应用程序结构(完整的 JavaScript 堆栈) [英] Want to get crystal clear about NodeJS app structure (Full JavaScript Stack)

查看:17
本文介绍了想要清楚地了解 NodeJS 应用程序结构(完整的 JavaScript 堆栈)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道一个典型的 NodeJS 应用程序的结构,因为我阅读和查看项目的次数越多,我就越困惑,特别是对于这样的问题(或者在我更新这个问题后更是如此):

I would like to know the structure of a typical NodeJS app, because the more I read and see the projects, the more confused I am, specifically for questions like these (or even more after I updated this question):

  1. 以 MEAN 堆栈为例,据我所知,NodeJS 和 Express 负责服务器部分,提供服务器接口等.MongoDB 和 Angular 非常简单.

  1. Take the MEAN stack for example, from what I know, NodeJS and Express take care of the server part, providing the server interface, etc. MongoDB and Angular are pretty straightforward.

但是业务逻辑应该去哪里呢?假设我有一个包含函数的 controller.js,并且 route.js 文件将请求与此控制器函数绑定.我的问题是:这些文件属于/在哪个模块下运行(Express 还是 NodeJS?)

But where should the business logic go? Say if I have a controller.js which contains a function, and the route.js file binds the request with this controller function. My question is: under which module these files belong to/run under (Express or NodeJS?)

NodeJS 应用的起点在哪里?假设 index.php 是 PHP 应用程序的起点,但 NodeJS 应用程序的起点在哪里?我可以看到所有 Nodejs 项目都有一个名为 server.jsapp.js 等的文件(包含类似 module.exports = app;) 但是 NodeJS 怎么知道要查找和执行哪个文件呢?

Where is the starting point of a NodeJS app? Say index.php is the starting point of a PHP app, but where is it for NodeJS app? I can see that all Nodejs projects have a file called server.js or app.js, etc.(containing something like module.exports = app;) But how can NodeJS know which file to find and execute?

我是 NodeJS、Express、sequelize.js/Mongoose、Jade/EJS 的新手,但想开始一个 NodeJS 项目.您能否详细说明每个模块提供的实际功能以及完整的 JS 堆叠 NodeJS 应用程序的典型结构的一般介绍?提前致谢!

I am a fresh noob on NodeJS, Express, sequelize.js/Mongoose, Jade/EJS but want to get started on a NodeJS project. Could you please elaborate on the actual function that each modules provide and a general introduction of the typical structure for a full JS stacked NodeJS app? Thanks in advance!

推荐答案

好吧,这是一个相当广泛的问题,我绝对不是专家,但我会尽我所能.

Alright, this is a pretty broad question and I'm definitely no expert, but I'll do my best here.

TL;DR

  • routes 是控制器,当用户将浏览器导航到应用程序中的特定路径时,它们会告诉执行什么逻辑,包括要呈现哪些视图以及要向这些视图发送哪些数据
  • models 就是这样 - 应用程序中的数据模型
  • module.exports = 告诉文件它导出"的确切内容,即需要从您的主应用文件执行或访问的代码.
  • require(..) 包含一个模块.您可以在变量上设置它,以便稍后调用模块函数,或者如果 module.exports 返回的只是执行一个函数.
  • routes are controllers that tell what logic to execute when a user navigates their browser to a certain path within your app, including which views to render and what data to send to those views
  • models are just that - data models within your application
  • module.exports = tells a file what exactly it "exports", that is what code needs to be executed or accessible from your main app file.
  • require(..) includes a module. You can set this on a variable so that you may call module functions later, or simply execute a function if that is all that module.exports returns.

结合使用这些技术可以帮助您为任何应用程序确定一个可靠的框架.

Combining these techniques can help you nail down a solid framework for any of your applications.

长答案

Express 为构建 Node.js 应用程序提供了可靠的框架.Node 完全独立于 Express,但由于 Express 的受欢迎程度,它们实际上是齐头并进的.安装后,Express 可用于生成一个脚手架 Web 项目(带有选项),如果您愿意,您可以在其上构建.

Express provides a solid framework for structuring your Node.js application. Node is completely independent of Express, but because of how popular Express is they practically go hand-in-hand. Once installed, Express can be used to generate a scaffold web project (with options) for you to build on top of if you'd like.

控制器

生成的项目将创建 /routes/index.js,它(如果您了解 MVC)本质上是您的主要 控制器.express 中的路由是这样写的:

A generated project will create /routes/index.js, which (if you understand MVC) is essentially your main controller. A route in express is written as so:

app.get('/path', function(req, res, next){ .. } );

让我们分解一下:我们的应用程序变量 (app) 被告知在对 '/path' 的 GET 请求中使用 req, res, next<执行匿名回调函数/code> 变量(分别为请求、响应、回调).我发现将其视为自定义事件处理程序很有帮助.

Lets break that down: our application variable (app) is being told that on a GET request to '/path' to execute an anonymous callback function with req, res, next variables (request, response, callback respectively). I find it helpful to think of this like a custom event handler.

在这一点上需要注意的是,我们也可以使用相同的语法调用 app.post 来发布到 URL,而不是获取.

Its important to note at this point that we could also call app.post with the same syntax for posts to a URL as opposed to gets.

在我们的匿名回调中,我们处理任何传入数据并为用户呈现视图.这是我的大部分业务逻辑的最终结果,因此这里不使用匿名函数实际上是有意义的.下面是一个只显示主页的基本回调示例:

Within our anonymous callback, we handle any incoming data and render a view for the user. This is where most of my business logic ends up, so it actually makes sense to NOT use anonymous functions here. Here's an example of a basic callback that just displays a homepage:

app.get('/', function(req, res, next){

    //some business logic

    res.render('views/home');
});

当用户尝试获取我们应用程序的索引路径 (/) 时,我们只需渲染我们的 home 视图,该视图从项目的根目录存储在 views 文件夹中.

When the user tries to GET the index path of our application (/), we simply render our home view that, from the root of our project, is stored in a views folder.

但是,如果我们想将其模块化,这样我们就不会在主 app.jsserver.js 中声明所有路由?

But what if we want to modularize this so that we aren't declaring all of our routes in our main app.js or server.js?

我们在模块中使用 module.exports = .. 来告诉我们的服务器究竟要包含什么.在我的控制器中,我导出了一个函数,该函数将应用程序作为参数并使用它来定义我们的路由,如下所示:

We use module.exports = .. in our modules to tell our server what exactly to include. In my controller, I export a single function that takes the application as an argument and uses that to define our routes like so:

控制器/User.js

 module.exports = function(app){

    app.get('/users', function(req, res){
        var users = req.db.collection('users').find();
        if (!users) {
            console.log("no users found");
            res.redirect('/');
        } else {
            res.render('users/index', {users : users});
        }
    });

};

不用担心 req.db 代码,我将数据库附加到应用程序中的请求,但默认情况下不会这样做.简单理解我在这里得到一个用户"列表,如果没有的话,将用户重定向到我的应用程序的索引.

Don't worry about the req.db code, I attach the database to the request in my application but that isn't done by default. Simply understand that I'm getting a list of 'users' here, and redirecting the user to the index of my app if there aren't any.

模型

Mongoose 为我们提供了一个很好的模型编写界面.使用 mongoose,编写模型是一个三步过程:

Mongoose provides us with a great interface for writing models. With mongoose, writing models is a three step process:

  • 定义架构
  • 定义模型逻辑
  • 生成并导出模型

这是一个 User 模型的示例:

Here is an example of a User model:

模型/User.js

var mongoose = require('mongoose'),
    userSchema = new mongoose.Schema({

        name: { type: String, required: true },
        joinDate: {type: Date, default: date.now }

    }),
    User = mongoose.model('user', userSchema);

module.exports = user;

服务器应用

module.exports 用于帮助我们为代码库定义一些模块化.当我们运行一个节点应用程序时,我们最终会运行一个 JavaScript 文件(您已经看到该文件带有 server.jsapp.js).

module.exports is used to help us define some modularity to our codebase. When we run a node application, we're ultimately running a single JavaScript file (you've already seen that file with server.js or app.js).

为了防止这个文件因多个模型和路由而变得太大,我们使用 require(module) 来包含来自其他 JS 文件的代码.module 在我们的例子中是我们想要的模块的路径.如果您有以下文档结构:

To keep this file from getting too big with multiple models and routes, we use require(module) to include code from other JS files. module in our case would be a path to the module we want to require. If you have the following doc structure:

| Controllers
    - User.js
| Models
    - User.js
| Views
app.js

要在 app.js 中包含您的用户控制器,您可以编写:require('./Controllers/User').由于我们的控制器模块只是导出函数,因此我们可以在 require 语句之后立即调用该函数,只需在末尾添加括号(使用所需的任何参数).包括我的控制器看起来像这样:

To include your user controller from app.js, you would write: require('./Controllers/User'). Since our controller modules simply export functions, we can call that function immediately after our require statement by simply adding parentheses at the end (with whatever parameters are required). Including my controllers looks like so:

require('./Controllers/User')(app)

我正在传递实际的应用程序,因为我的模块(如下)只是导出了一个函数,该函数将业务逻​​辑添加到我的应用程序的路由中.这只需要被调用并且从不使用,所以我不会将我的控制器捕获为变量以便稍后调用方法.

I'm passing in the actual app, because my module (below) simply exports a function that adds business logic to my app's routes. This only needs to be called and never used, so I don't capture my controller as a variable to call methods on later.

包含模型有点不同,因为我们可能想要执行模型定义的一些操作.我们可以通过稍微修改一下我们的需求代码来做到这一点:

Including models is a little different, since we may want to perform some operation that our model defines. We can do this by changing up our require code just a bit:

var User = require('./Models/User');

现在我们可以随时调用 User 模型的方法.Mongoose 免费为我们提供了许多基本功能:

Now we can call methods of our User model whenever. Mongoose gives us a lot of base functionality for free:

User.find({}, function(err, users){ .. });

上面的函数会找到我们所有的用户,然后执行一个带有潜在 err 的匿名函数(如果没有问题,则为 null),然后是 JSON 格式的用户列表.很漂亮.

The above function will go find all of our users, and then execute an anonymous function with a potential err (is null if no issues) and then a list of our users in JSON format. Pretty nifty.

结合所有这些概念是您使用 Express 和 Node.js 创建基本 Web 应用程序的方式.如果有任何关于我如何使用 Express 的说明,请在评论中告诉我.这是非常表面的知识,我建议深入研究文档并查看插件以扩展您的应用程序的功能.祝你好运!

Combining all of these concepts is how you create a basic web application using Express and Node.js. Please let me know in the comments if there's anything I can clarify about how I use Express. This is very surface level knowledge, and I suggest digging into documentation and looking at plugins to extend the capabilities of your apps. Good luck!

这篇关于想要清楚地了解 NodeJS 应用程序结构(完整的 JavaScript 堆栈)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆