Node JS,Express结构和Require混淆

6

这让我很困惑。我是NodeJS的新手,到目前为止我非常喜欢它,但有些事情却让我感到困扰。有人给了我一个非常基本的Node项目起点,但我不确定该如何在谷歌上搜索相关内容。

//myapp/server.js

var config  = require('./config');
var app     = express();
var api     = require('./app/routes/api')(app, express); // <-- this?

app.use('/', api);

var server = app.listen(3000, function () {
    console.log('\n============================');
    console.log(' Server Running on Port 3000  ');
    console.log('============================\n');
});

然后有一个包含路由的api.js文件。

//myapp/app/routes/api.js

var config   = require('../../config');
var mysql    = require('mysql');

module.exports = function(app, express) {

    var api = express.Router();

    api.all('/', function(req, res) {...});

    api.all('/route-two', function(req, res) {...});

    api.all('/another-route', function(req, res) {...});

    return api;
}

理想情况下,我希望能将这里正在发生的事情分解成更有组织的结构,但是,我想确切地了解我正在做什么。
让我困惑的主要是这一行。
var api = require('./app/routes/api')(app, express);

我不知道您可以在没有 . 或其他连接它们的东西的情况下将()()放在一起。能否有人解释一下正在发生的事情?
此外,(app,express)的目的是什么?似乎将 app express 传递给应用程序的 api 部分,以便可以达到其范围?我错了吗?
如果有更简洁的方法,我很想得到一些见解。感谢任何想法。
谢谢!
编辑 为确保我理解...
var api = require('require this file')(params available to this file);

将任何需要的要求从api.js移动到server.js,然后将其作为参数包含。

var api = require('./app/routes/api')(config, app, express, mysql);

编辑

在得到来自@AhmadAssaf @Gurbakhshish Singh和@guy mograbi的更多有用反馈之后,我想要在另一个文件中使用的模块不应该通过require()被调用。相反,它们应该通过第二个括号传递进来。

//.server.js
var config = require('./config');
var app    = express();                                          
var api    = require('./app/routes/api')(config, app, express); 
                                           |      |        |
                              _____________/______/________/
                             /      /      /
//.app/routes/api.js         |      |      |
module.exports = function(config, app, express) {

    var api = express.Router();

    // code to handle routes
}

可能我的理解有误,但根据我所了解的情况来看。
//.server.js
var config = require('./config');
var app    = express();

var register = require('./app/routes/register')(config, app, express); 
var login    = require('./app/routes/login')(config, app, express); 
                                               |      |        |
                              _________________/______/________/
                             /      /      /
//.app/routes/login.js      |      |      |
module.exports = function(config, app, express) {...handle login...}

//.app/routes/register.js    
module.exports = function(config, app, express) {...handle registration...}    

etc. etc.

希望我的想法是正确的。感谢大家对此的帮助! :)


1
是的,这就是它们被注入的方式。 - Gurbakhshish Singh
4个回答

3

基本上,您需要理解以下几点:

  • module.exports 将一个 Javascript 对象包装起来并导出它,以便作为可插拔的代码块在 node.js 应用程序中使用。
  • 被包装的 Javascript 对象可以是 JSON 对象、Javascript 变量、函数等等。

您在 api 模块中有一个接受两个参数的函数。当您需要该模块时,您希望将一些构造函数传递给该函数,这就是第一个 () 中模块名称后面的第二个 () 的用途。

在程序中只需要一次 require express 并将变量传递到各处,这更或多或少是单例模式。您还可以将 config 对象传递给 api 模块,而不是再次 require 它 :)


好的,这有点像 require('./this/file').module.exports(app, express) 然后我可以将它们全部放在 server.js 中,而不是添加到子文件中require('./this/file')(config, app, express, mysql)?将 mysql 的 requires 放在 server.js 中以便组织? - Trozdol
@Trozdol 我不明白你所说的 require('./this/file').module.exports(app, express) 是什么意思。module.exports 将一块 JavaScript 代码公开为模块,而 require 将“导入”该模块。至于你的第二个问题,你可以在服务器上拥有所有的 requires 并开始传递它们,但这并不干净。我的做法是在需要时每次 require 每个模块,如果你需要一个 singleton 的配置或选项对象,那么我会在第一次使用时创建它并传递它。 - AhmadAssaf
@Trozdol,请看这里https://github.com/ahmadassaf/chatter/blob/master/server.js 这是我写的一些代码示例,你可以查看各种导出和要求。 - AhmadAssaf
好的,感谢澄清。我对我的帖子进行了编辑,希望能更好地解释我的问题。在编辑后,我看到了你关于在需要时包含模块的评论。 - Trozdol

1
var api = require('./app/routes/api')(app, express);

等价于:

var myFunc = require('./app/routes/api');
var api = myFunc(app, express);

由于NodeJS的模块加载过程,require('...')将被导出路径处的代码片段插入,它可以是对象、函数、简单变量等。
至于()(),NodeJS将使之成为类似于function(){}()的函数,在您的情况下,这是有效的JavaScript,并且编写IIFE(立即调用函数表达式)代码非常有用。

我忘了提到应用程序和Express是注入的,因为您不希望有多个实例。 - Gurbakhshish Singh
这被称为单例模式:https://en.wikipedia.org/wiki/Singleton_pattern - solick
我熟悉单例模式,我犹豫使用这个术语的唯一原因是它是面向对象编程中的设计模式之一,尽管您可以实现类似的行为,但JS并不完全是面向对象的。 - Gurbakhshish Singh

1

问题1

explain ()()

在任何函数可以返回函数的语言中,都可以使用此语法。想象一下以下情况:

function world(){ ... }

function hello(){
     return world;
}

 // ===> 
hello()() // ==> would invoke hello and then world. 

当你看到 require('..')() 时,它意味着 require('..') 返回一个函数。你可以通过写入以下内容来实现:
module.exports = function(){}

该函数返回另一个函数 - 在您的情况下,这意味着express.Router();返回一个函数。

问题2

有更简洁的编写方式吗?

这是一个讨论..很难回答。这取决于您的喜好。我能想到的唯一可能帮助您得出答案的事情是使用express生成器并查看express团队使用的结构..这可能是最干净的。

express可以为您生成一些起始代码的项目。只需使用npm install -g express安装它,然后运行express - 它将在您运行它的相同目录中为您生成项目。

查看生成的项目。建议按照相同的模式进行操作 - 这是我启动项目时所做的。

如果仍不清楚或需要我进一步阐述,请评论,我将编辑答案。


好的,谢谢!我觉得这很有道理。今天之前我还没有意识到这可以做到。看起来非常方便。感谢您的解释!:D - Trozdol

0

api.js 中的 module.exports 是一个函数,接受两个参数:app 和 express。因此,当你在 server.js 中使用 require('./app/routes/api') 引用它时,返回的值就是这个函数。由于它是一个函数,你可以通过在它后面加上括号,并传入它所需要的参数(app 和 express),来直接调用它,像这样:require('./app/routes/api')(app, express)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接