2013-02-14 17 views
17

Şu anda bir süredir Backbone uygulamaları geliştiriyorum ve sadece Backire with Require.js kullanmayı öğrenmeye başlıyorum.Backbone/Require Uygulamasındaki paylaşılan nesneler için en iyi uygulama

Düzeltmeyi geri yüklediğim omurga uygulamasında şu şekilde bir ad alanı tanımladım: App.model.repo. Bu model farklı görüşlerde tekrar tekrar kullanılmıştır. Aynı şeyi birkaç koleksiyonla yapıyorum, örneğin, App.collection.files. Bu modeller ve koleksiyonlar ilk dizin dosyası isteği ile önyüklenmiştir.

Bu önyükleme verilerini almak için harika bir yol gibi görünen this example buldum. Ancak, bu modelleri ve koleksiyonları görünümler arasında yeniden kullanmanın/paylaşmanın en iyi yolu ile mücadele ediyorum.

Üç olası çözümü düşünebilirim. Hangisi en iyisi ve neden? Yoksa tamamen eksik olduğum başka bir çözüm var mı?

Çözüm 1

endeksinde bu ortak modüller ve koleksiyonları (onlar bootstrapped zaman) tanımlayın ve sonra (initialize ait) bir seçenek olarak her Backbone görünümüne boyunca onları geçmek.

define(['jquery', 'underscore', 'backbone', 'handlebars', 'text!templates/NavBar.html'], 
    function($, _, Backbone, Handlebars, template){  
     return Backbone.View.extend({ 
      template: Handlebars.compile(template), 
      initialize: function(options){ 
       this.repoModel = options.repoModel; // common model passed in 
      } 
     }); 
    } 
); 

Bunlar temiz kadarıyla ayrılması gibi görünüyor, ama işler her tarafa geçirilen tonlarca hızlı korkak alabilir.

Çözüm 2

bir globals modülünü tanımlayın ve buna yaygın olarak kullanılan modeller ve koleksiyonlar ekleyin.

// models/Repo.js 
define(['backbone'], 
    function(Backbone){ 
     return Backbone.Model.extend({ 
      idAttribute: 'repo_id' 
     }); 
    } 
); 

// globals.js (within index.php, for bootstrapping data) 
define(['underscore', 'models/Repo'], 
    function(_, RepoModel){  
     var globals = {}; 

     globals.repoModel = new Repo(<?php echo json_encode($repo); ?>); 

     return globals 
    } 
); 

define(['jquery', 'underscore', 'backbone', 'handlebars', 'text!templates/NavBar.html', 'globals'], 
    function($, _, Backbone, Handlebars, template, globals){ 
     var repoModel = globals.repoModel; // repoModel from globals 

     return Backbone.View.extend({ 
      template: Handlebars.compile(template), 
      initialize: function(options){ 

      } 
     }); 
    } 
); 

Bu çözüm, AMD'nin tüm noktasını bozuyor mu? 3

Çözüm bazı modellerde yapın ve koleksiyonları (etkili onlara Singletons yapma) yerine yapıcı, bir örneğini döndürür.

// models/repo.js 
define(['backbone'], 
    function(Backbone){ 
     // return instance 
     return new Backbone.Model.extend({ 
      idAttribute: 'repo_id' 
     }); 
    } 
); 

// Included in index.php for bootstrapping data 
require(['jquery', 'backbone', 'models/repo', 'routers/Application'], 
    function($, Backbone, repoModel, ApplicationRouter){ 
     repoModel.set(<?php echo json_encode($repo); ?>); 

     new ApplicationRouter({el: $('.site-container')}); 
     Backbone.history.start(); 
    } 
); 

define(['jquery', 'underscore', 'backbone', 'handlebars', 'text!templates/NavBar.html', 'models/repo'], 
    function($, _, Backbone, Handlebars, template, repoModel){ 
     // repoModel has values set by index.php 

     return Backbone.View.extend({ 
      template: Handlebars.compile(template), 
      initialize: function(options){ 

      } 
     }); 
    } 
); 

Bu benim endişe bir yapıcı ve bir örnek neyi ne olduğu konusunda gerçek kafa karıştırıcı alabilir.

sonu

Buraya kadar okumaya varsa, müthiş! Zaman ayırdığınız için teşekkürler.

+0

Varolan uygulamamı yeniden kodlayarak, 1. ve 3. seçeneklerden birini denedim. Seçenek 1 hızla, her yere ihtiyaç duyulan seçeneklerle, her şeye ihtiyaç duymayan bir modülle, sadece ihtiyaç duyan bir çocuk modülüne ulaşmak için tüylü bir şekilde tüyler üretti. Sonunda, seçenek 3 bana daha temiz geliyor. Gerçek şu ki, şu anki projemde bu seçeneklerin tümünü kullanıyorum. Kısa kullanım ömrü elemanları için Seçenek 1. "ApiUrl" (ortak kök url) gibi basit şeyler için Seçenek 2. Proje çapında kullanılan omurga modelleri ve koleksiyonlar için Seçenek 3. – Bart

+0

Maddi olarak ilgili: http://stackoverflow.com/a/15528785/158651 – Bart

cevap

4

Benim durumumda, seçenek 3'u tercih ederim. Karışıklığı önlemek için, her bir tekil örneği, instances adlı kendi klasörüne koydum. Ayrıca, model/collection'u instance modülünden ayırma eğilimindeyim. Her modül (örneğin ad aracılığı durumda değil) bağımlılıklarından tanımlamak zorunda kalır gibi bu seçeneği tercih

define([ 
    "instance/photos" 
], function(photos) { /* do stuff */ }); 

:

Sonra, ben sadece onları arayın. Çözüm 2 işi yapabilirdi, ama AMD kullanıyorum, modülümü mümkün olduğunca küçük istiyorum - artı tutmak onları küçük tutmayı daha kolay hale getiriyor.

Son olarak, birim testi hakkında, sahte verileri kullanmak için yalnızca birim sınamamın içindeki örneği yeniden tanımlayabilirim. Bu örnek, repo https://github.com/tbranyen/github-viewer

bir göz alacağını https://github.com/iplanwebsites/newtab-bookmarks/tree/master/app

+0

Örnekler klasörü fikrini beğeniyorum. Işe yarayabilir. [Bu kod] 'a bakmadan (https://github.com/iplanwebsites/newtab-bookmarks/blob/master/app/instances/settings.js),' uygulamanızın 'temelde sizin' globals'ınız olduğu anlaşılıyor. ? Bu, ** Seçenek 2 ** 'ye daha yakın görünüyor. – Bart

+0

Evet ve hayır, 'app' global bir nesnedir ve her zaman çağrı yapar. Ancak, bir isim alanı olarak kullanılmaz ve yalnızca bazı genel yardımcı işlevler döndürür; her yerde kullanılan genel yapılandırmaları belirler (Düzen Yöneticisi ve i18n kitaplığı normal olarak). Mükemmel bir dünyada, 'uygulama modülünü kullanmazdım ve' require.config 'içinde kütüphane yapılandırması kurardım, ama ne yazık ki, RequireJS sadece shim modülleri için init'i destekliyor. –

+1

Oh, hey, ne demek istediğini gördün. Bu projenin bir uygulama alanı olarak "app" kullandığını fark etmediniz. Bunu geçmişte yapıyordum, ama artık yeterince esnek olmadığından değilim, bu bir _relicat_. Örneklerin/ayarların kullanıldığı yere bakarsanız, ad alanını değil yalnızca dönüş değerini kullandığınızı görürsünüz. –

1

: Yani, kesinlikle, opsiyon 3.

Sen ATM'ye üzerinde çalışıyorum bir açık kaynak uygulamasında bu modelin bir örnek görebilirsiniz Bu, omurga kazanı plakasının (https://github.com/tbranyen/backbone-boilerplate) Omurga Kazan plakasının çok fazla gereksiz tüy dökülmesine neden olan bir çalışma örneğidir, ancak bu konuda gerçekten yararlı olan şey, karmaşık javascript uygulamaları geliştirmek için ortak kalıplar üzerinde bazı açık talimatlar vermesidir.

ben denemek ve bunu

1

:) birisi beni dövmek değilse ben bu avoidusingsingletons genellikle iyidir Çözüm 1. tercih ve (daha spesifik soru cevap sonradan bugün geri gelirim gloebals kullanarak, özellikle RequireJS kullandığınız için, kaçınılması gereken bir şeydir.

İşte Çözüm 1 için aklınıza gelebilecek bazı avantajları şunlardır:

Bu görünüm kodu daha okunabilir hale getirir. Modüle ilk kez bakan birisi, kullandığı modellerde initialize fonksiyonuna bakarak hemen görebilir. Eğer globals kullanırsanız, dosyaya 500 satır aşağı erişilebilir.

Görüntüleme kodu için birim sınamalarını yazmayı kolaylaştırır. Testlerinizde sahte modeller geçirebileceğinden beri.

+0

Harika puan. Teşekkürler. – Bart

+1

Paul'un bakış açısına katılıyorum. Seçenek 1'i kullanmak, omurga ile ilgili nesneleri kolayca test etmenize ve tüm kodunuzun birden çok modüle ve nesneye bölünmesinden dolayı çok okunabilir olmasını sağlar. Seçenek 1'e rağmen eklemek istediğim nokta omurga pub/sub modelini güçlendirmeye yardımcı olur. Etkinliği kullanmak, işlevi doğrudan çağırmaktan çok daha iyidir! – adrian

+1

Okunabilirlik noktanıza katılmıyorum. this.repoModel options.repoModel olarak ayarlanıyor. Seçeneklerin ne olduğunu ve seçeneklerin ne olduğunu bilmenin bir yolu yok mu? Seçenekler ve options.repoModel'de ne olduğunu anlamak için, bu modülü başlatan kodu takip etmeliyiz. Bu varsayımdan biraz uzaklaşabilirim, ama bart ihtiyaç duyduğundan dolayı, modüller niçin işlevler aracılığıyla geçiyor? – andyzinsser