2012-06-23 2 views
2

Я пытаюсь выработать правильный шаблон для использования Singleton, который инициализируется вызовом AJAX. Это упрощенный пример того, что я уже работаю.javascriptMVC singleton с шаблоном проектирования инициализатора AJAX

Работает так, как ожидалось, но я чувствую, что это не «правильный» способ, и есть способ связать обратный вызов инициализатора с вызовом успешного выполнения текущего выполняемого запроса 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()) }); 

Или есть более простой способ сделать это? Какую концепцию мне не хватает, что облегчит жизнь?

+0

может стоять, чтобы улучшить комментарий! – cliveholloway

+2

Кроме того, forEach не будет работать в IE, а новый Array() следует избегать (вместо этого писать [onSuccess]). – noah

ответ

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 plugin (раскрытие: Я основной автор), который реализует функционал форма инъекции зависимости.

Если вы должны были использовать 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:"); 

Для крупных проектов с большим количеством одиночек или просто отсроченных данных, инъекционные весы лучше, чем глобальные переменные.

+0

Большое спасибо за ваш подробный ответ. Я все еще изучаю современные образцы дизайна JS, и это заставляло меня слишком сильно царапать голову. – cliveholloway

Смежные вопросы