我有一个导出函数的Node.js模块:
module.exports = function(data){
return {
// return some object
}
};
我希望在这里使用单身模式,但没有太多额外的麻烦。这是一个库,我的库代码可能会偶然多次调用此函数,但我需要依赖用户来定义代码,所以我不能保证它们将实现适当的单例模式。
如果导出的函数被多次调用,是否有一个好的模式可以用来抛出错误?
我在想这样的事情:
const fn = require('./user-defined-module');
const someObject = fn();
// next I want to somehow mark this module as having been loaded
明确说明,以下情况并不好:
var loaded = null;
module.exports = function(data){
if(loaded) {
return loaded;
}
// do some stuff
return loaded = {
// return some object
}
};
对于一些可能足够的用例,但我希望废除标准的单例代码,原因有几个。
我不认为monkeypatching require函数会对此有所帮助,但也许。
现在我加载这样一个模块的代码是这样的:
const fn = require('./user-defined-module');
const obj = fn.apply(ctx, some_args);
问题是我的代码库中的其他地方我可以调用
const obj = fn.apply(ctx, some_args);
一次。代码库越来越大,我想快速失败。
在我看来,最好的办法就是重新定义fn,一旦它被称为第一次。
(1)我必须将局部变量fn设置为类似
的东西fn = function(){
throw 'whoops you messed up'
}
更重要的是(2)
我必须将module.exports值设置为
module.exports = function(){
throw 'whoops you messed up'
};
希望有所作为
答案 0 :(得分:1)
将一些数据传递到函数库时,或者当您的库第一次调用该函数时,将其附加到函数中。然后使用该属性保护您的库调用方法:
function callUserFn() {
let fn = require('./user-defined-module');
if ( !fn._calledByMyLibrary ) {
fn._calledByMyLibrary = true
return fn()
} else {
throw new Error('Already called')
}
}
函数的属性非常罕见,因此它不太可能与先前存在的任何内容发生冲突,并且避免了与Node内部的混乱。
用函数Proxy替换函数库的函数可以在较新的Node环境中实现相同的功能。然后可以在代理中而不是在函数上设置called
数据。
let fn = new Proxy(require('./user-defined-module'), {
apply(target, that, args){
if ( fn.called === true ) throw new Error('Already called')
fn.called = true
return target.apply(that, args)
}
})
fn('test','one')
fn('test','two') // => Error: Already called...