如果两次调用导出的模块函数,则抛出错误

时间:2017-03-19 05:42:44

标签: node.js design-patterns singleton singleton-methods

我有一个导出函数的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'
};

希望有所作为

1 个答案:

答案 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...