2

我正在尝试为使用 AJAX 调用初始化的 Singleton 制定正确的模式。这是我已经工作的一个简化示例。

它按预期工作,但我觉得这不是“正确”的方式,并且有一些方法可以将初始化程序的回调挂钩到当前正在运行的 ajax 请求的成功调用中,我担心可能会有一场比赛条件与数组方法。我在正确的轨道上吗?

var singletonObj;
$.Class("SingletonTest", {
  init: function(onSuccess) {
    if (singletonObj) {
      if (singletonObj.ajaxLoaded) {
        onSuccess(singletonObj);
      }
      else {
        singletonObj.callbacks.push(onSuccess);
      }
    }
    else {
      singletonObj = this;
      singletonObj.callbacks = new Array(onSuccess);
      singletonObj.count=0;

      $.ajax({
        url: "/path/to/json/config",
        method: "GET",
        success: function (res) {
          singletonObj.data = res.meta_data;
          singletonObj.ajaxLoaded = true

          singletonObj.callbacks.forEach(function(callback) {
            callback(singletonObj);
          });
        }
      });
    }
  },
  counter: function() {
    return this.count++;
  }
});

new SingletonTest( function(obj) { console.log("First call: "+obj.counter() ) });
new SingletonTest( function(obj) { console.log("Second call: "+obj.counter() ) });
new SingletonTest( function(obj) { console.log("Third call: "+obj.counter() ) });

或者有没有更简单的方法来做到这一点?我在这里缺少什么概念可以让生活更轻松?

4

1 回答 1

2

由于您正在寻找“正确”的方式,因此这里有一些一般说明:

  1. 您不需要单例类(JavaScript 不是 Java)。只需将其设为全局 obj 或更好的函数即可。

  2. $.Deferred是你的朋友。$.ajax返回一个承诺。

这是单例的功能模式:

// creates a lazy singleton from a factory function
function singleton(factory) {
    var deferred;
    return function() {
        return deferred || (deferred = factory());
    };
}

// declare your specific singleton
var SingletonTest = singleton(function() {
    return $.ajax({
        url: "/path/to/json/config",
        method: "GET"
    }).pipe(function(obj) {
        // pipe lets you modify the result
        // here we add the counter method
        var count = 0;
        obj.counter = function() {
            return count++;
        };
        return obj;
    });
});

// use it
SingletonTest().then(function(obj) {
    console.log("First: "+obj.counter());
});

SingletonTest().then(function(obj) {
    console.log("Second: "+obj.counter());
});

如果您发现自己经常使用这种模式,那么有一个JMVC 插件(披露:我是主要作者)实现了依赖注入的功能形式。

如果您要使用Inject,它将如下所示:

var cache = Inject.cache();
var Injector = Inject(
    cache.def('SingletonTest',function() {
        return $.ajax({
            url: "/path/to/json/config",
            method: "GET"
        }).pipe(function(obj) {
            var count = 0;
            obj.counter = function() {
                return count++;
            };
            return obj;
        });
    })
);

var logCount = Injector('SingletonTest',function(obj,message) {
    console.log(message+obj.counter());
});

logCount("First:");
logCount("Second:"); 

对于具有大量单例或只是延迟数据的大型项目,注入比例比全局变量更好。

于 2012-06-23T16:03:13.680 回答