1

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

希望这有点道理

4

1 回答 1

1

当传递给您的库或当您的库第一次调用该函数时,将一些数据附加到函数。然后使用该属性保护您的库对方法的调用:

function callUserFn() {
  let fn = require('./user-defined-module');
  if ( !fn._calledByMyLibrary ) {
    fn._calledByMyLibrary = true
    return fn()
  } else {
    throw new Error('Already called')
  }
}

函数的属性非常罕见,因此它不太可能与任何预先存在的东西发生冲突,并且它避免了与 Node 内部的混淆。

用函数的代理替换函数的库引用可以在较新的 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...
于 2017-03-19T08:05:18.717 回答