node.js 中所需的结构化库的最佳实践

Posted

技术标签:

【中文标题】node.js 中所需的结构化库的最佳实践【英文标题】:Best practice for structuring libraries to be required in node.js 【发布时间】:2013-07-29 23:30:34 【问题描述】:

我有几个包含辅助函数的实用程序库,我想加载它们以便可以从控制器中使用它们,我想知道 在节点中编码实用程序库的最佳实践是什么。

我有点困惑,因为有几种方法可以做到这一点,我不确定哪种方法最好/更合适/更可靠。这里有 2 个选项,但我想知道它们是否是最好的(例如,我见过使用 module.exports = exports = function() 等的 sn-ps)

//option1.js


"use strict";

module.exports =  function()

     exports.test1 =  function() console.log('hi I'm test1');
     exports.test2 =  function() console.log('hi I'm test2');
     return exports;
;

//option2.js

"use strict";

module.exports =  

     test1 : function() console.log('soy test1'),
     test2 :  function() console.log('soy test2')

;

//test_controller.js

/* Requiring helpers in different ways */
var option1 = require('./option1.js')();
var option2 = require('./option2.js');

【问题讨论】:

请注意,接受的答案和这个问题已经很老了,并且 JS 更新了导入/导出语句,以提高性能和可读性,在撰写本文时,当前接受的答案中没有解决这些问题。 @KyleBaker 你能举个例子吗? 我现在没有时间写出符合我标准的答案。但是,MDN 有示例。目前可在此处进行深入探索:exploringjs.com/es6/ch_modules.html 【参考方案1】:

我认为我的文件分为 3 个部分:

第 1 节:CommonJS 依赖项

var lib1 = require("lib1");
var lib2 = require("lib2");

您不需要任何额外的包装函数。所有节点模块都是automatically wrapped by node.js 在一个函数中,这样做没有任何好处,只会增加混乱

第 2 部分:纯 javascript 代码

如果需要,这应该几乎完全是带有一些支持变量或***模块代码的函数。

var MY_CONST = 42;

function helper1() 
    //excellent code here


function helper2() 
    //excellent code here

保留第 2 节纯 JS。不要在这个中间的“纯”部分使用 commonJS 成语。不要使用moduleexportsrequire 等。这只是我个人的指导方针,因为 JS 本身是稳定的,但是打包到模块中仍然有很多变化,最好保留 CommonJS 位是无关的,并且可能会与有趣的代码分开而改变。 ECMAScript 6 模块最有可能在几年内取代 CommonJS,所以通过保留第 2 节纯 ECMAScript 5 并制作一个我喜欢称之为“CommonJS Sandwich™”的方式,让自己更容易做到这一点。

第 3 部分:CommonJS 导出

exports.helper1 = helper1;
exports.helper2 = helper2;
将所有导出放在最后还可以让您快速了解公共 API 是什么,并防止由于不小心复制/粘贴而意外导出属性。 我更喜欢上面的exports.foo = foo; 语法,而不是将module.exports 分配给一个新的对象字面量。我发现这避免了对象文字的最后一个属性的尾随逗号问题。 用你的requireexports 语句做任何其他事情几乎肯定是没有必要的,而且是不必要的花哨或魔法。在你进阶之前,不要在这里做任何花哨的事情。 (即便如此,如果你不是 TJ Holowaychuk,你可能只是在傻)

我应该导出什么

单个函数(@substack 风格)

function degreesToRadians(degrees) 

module.exports = degreesToRadians;

保持小而简单。

函数对象

如果你的模块是一组辅助函数,你应该导出一个包含这些函数的对象作为属性

var foo = require("foo");

function doubleFoo(value) 
  return foo(value) * 2;


function tripleFoo(value) 
  return foo(value) * 3;


exports.doubleFoo = doubleFoo;
exports.tripleFoo = tripleFoo;

构造函数

如果你的模块是面向对象使用的类设计,导出构造函数

function GoCart() 
  this.wheels = 4;


GoCart.prototype.drive = function drive() 
  //vroom vroom


module.exports = GoCart;

工厂/配置关闭函数

一旦您掌握了上述 2 种模式(真的!)并有信心导出一个带有选项的工厂函数,并且可能会做一些其他动态的事情,那就去做吧,但是如果有疑问,请坚持前 2 个更简单的选择.

//do-stuff.js
function doStuff(howFast, what) 
   return "I am doing " + what + " at speed " + howFast;


function setup(options) 
  //The object returned by this will have closure access to options
  //for its entire lifetime
  return doStuff: doStuff.bind(null, options.howFast);


module.exports = setup;

所以你可以像这样使用它

var doStuff = require("./do-stuff")(howFast: "blazing speed");
console.log(doStuff.doStuff("jogging"));
//"I am doing jogging at speed blazing speed"

【讨论】:

优秀的答案@Peter。对模块设计非常有用。我会记住你的建议。请您提供有关“导出带有选项并可能执行其他一些动态内容的工厂函数”的示例/链接。我有兴趣在我的 node.js 代码中应用更多架构技术。 这个答案已经过时了,因为它没有解决优越的新导出/导入语法。它仍然是很好的信息,但不完整,并且新语法有性能优势(可以说,还有可读性改进)。 呃,从节点 v6 开始,仍然不支持导出/导入语法。我们在这里讨论的是非转译的 node.js,而不是一般的 ES2015。 赞成您对导出模块的看法。exports = (a, b) => return a + b 表示箭头函数 我会避免这种情况。我喜欢将 commonjs 语法与实际的实现代码分开。命名函数也可以提供更好的堆栈跟踪,因此有助于调试命名它们。【参考方案2】:

对于无状态实用程序库,option2.js 是要走的路,因为不需要每次require 时都执行module.exports 中的代码,这就是当你打电话给require('./option1.js')() 使用option1.js

另一方面,如果你的模块暴露了构造函数,这些构造函数创建了持有状态的对象,那么你会想要 option1.js。例如,

person.js:

module.exports = function(firstName,lastName)
    this.firstName = firstName;
    this.lastName = lastName;
;

然后使用它:

var Person = require("./person");

var person1 = new Person("Foo","Bar");
var person2 = new Person("Joe","Shmoe");

option1.js(如上所示)的另一个优点是它允许您将参数传递到模块中。

【讨论】:

谢谢@go-oleg。关于用例和性能的非常有趣的 cmets :)

以上是关于node.js 中所需的结构化库的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

typescript node.js express 路由分隔文件的最佳实践

52合1Node.js 最佳实践大合集

库、“注入工厂”和扩展库的最佳实践

数据库设计的 10 个最佳实践

数据库设计的 10 个最佳实践

Node.js 上 MongoDB 连接的最佳实践是啥?