2013-02-14 25 views
17

Tôi đã phát triển các ứng dụng Backbone một thời gian ngắn và tôi chỉ bắt đầu học cách sử dụng Backbone với Require.js.Thực tiễn tốt nhất cho các đối tượng dùng chung trong Backbone/Require Application

Trong ứng dụng xương sống của tôi mà tôi đang tái cấu trúc, tôi đã xác định không gian tên như sau: App.model.repo. Mô hình này được sử dụng hơn và hơn nữa trong các khung nhìn khác nhau. Tôi làm điều tương tự với một vài bộ sưu tập, ví dụ: App.collection.files. Các mô hình và bộ sưu tập này được khởi động cùng với yêu cầu tệp chỉ mục ban đầu.

Tôi đã tìm thấy this example, trông giống như một cách tuyệt vời để có được dữ liệu được khởi động đó. Tuy nhiên, tôi đang đấu tranh với cách tốt nhất để sử dụng lại/chia sẻ các mô hình và bộ sưu tập này giữa các chế độ xem.

Tôi có thể nghĩ đến ba giải pháp khả thi. Điều nào là tốt nhất và tại sao? Hoặc là có một giải pháp tôi đang thiếu hoàn toàn?

Giải pháp 1

Xác định các mô-đun phổ biến và các bộ sưu tập trong chỉ mục (khi chúng được bootstrapped in), và sau đó vượt qua chúng cùng với nhau xem Backbone như một tùy chọn (của initialize).

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 
      } 
     }); 
    } 
); 

Đây có vẻ sạch sẽ như xa cách ly, nhưng có thể trở nên sôi nổi nhanh chóng, với hàng nghìn thứ được truyền khắp nơi.

Giải pháp 2

Xác định một mô-đun globals, và thêm các mô hình thường được sử dụng và các bộ sưu tập với nó.

// 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){ 

      } 
     }); 
    } 
); 

Giải pháp này có đánh bại toàn bộ điểm của AMD không?

Giải pháp 3

Làm một số mô hình và bộ sưu tập trở lại một ví dụ, thay vì một nhà xây dựng (có hiệu quả làm cho chúng Singletons).

// 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){ 

      } 
     }); 
    } 
); 

Điều này tôi lo lắng có thể gây nhầm lẫn thực sự về hàm tạo và ví dụ là gì.

End

Nếu bạn đọc đến đây, bạn là tuyệt vời! Cảm ơn đã dành thời gian.

+0

Tôi đã thử cả tùy chọn 1 và 3, bằng cách tái cấu trúc ứng dụng hiện có của tôi. Lựa chọn 1 nhanh chóng có lông, với các tùy chọn được truyền đi khắp mọi nơi, thường thông qua một mô-đun mà không cần tất cả, chỉ để có được một mô-đun con mà đã cần nó. Cuối cùng, lựa chọn 3 cảm thấy sạch hơn nhiều với tôi. Sự thật là tôi đang sử dụng tất cả 3 tùy chọn trong dự án hiện tại của mình. Tùy chọn 1 cho các phần tử vòng đời ngắn. Tùy chọn 2 cho những thứ đơn giản như "apiUrl" (url gốc chung). Tùy chọn 3 cho các mô hình xương sống và các bộ sưu tập được sử dụng rộng rãi. – Bart

+0

Tiếp tuyến liên quan: http://stackoverflow.com/a/15528785/158651 – Bart

Trả lời

4

Trong trường hợp của tôi, tôi thích tùy chọn 3. Mặc dù, để ngăn chặn sự nhầm lẫn, tôi đặt mọi cá thể đơn lẻ trong thư mục riêng của chúng có tên là instances. Ngoài ra, tôi có xu hướng tách riêng các model/collection từ mô-đun instance.

Sau đó, tôi chỉ cần gọi chúng trong:

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

Tôi thích tùy chọn này là mỗi mô-đun buộc phải xác định sự phụ thuộc của nó (mà không phải là trường hợp thông qua namespace ví dụ). Giải pháp 2 có thể thực hiện công việc, nhưng nếu tôi đang sử dụng AMD, tôi muốn mô-đun của mình càng nhỏ càng tốt - cộng với việc giữ cho chúng nhỏ làm cho việc thử nghiệm đơn vị trở nên dễ dàng hơn.

Và cuối cùng, về thử nghiệm đơn vị, tôi chỉ có thể xác định lại cá thể trong thử nghiệm đơn vị của tôi để sử dụng dữ liệu giả. Vì vậy, chắc chắn, tùy chọn 3.

Bạn có thể xem ví dụ về mô hình này trên một ứng dụng mã nguồn mở Tôi đang làm việc trên máy ATM: https://github.com/iplanwebsites/newtab-bookmarks/tree/master/app

+0

Tôi thích ý tưởng về một thư mục thể hiện. Điều đó có thể hiệu quả. Từ việc xem [mã này] (https://github.com/iplanwebsites/newtab-bookmarks/blob/master/app/instances/settings.js), có vẻ như 'ứng dụng' của bạn về cơ bản là' globals' của bạn, đúng ? Điều này có vẻ gần hơn với ** Tùy chọn 2 **. – Bart

+0

Có và không, 'ứng dụng' là một đối tượng toàn cục và luôn gọi. Tuy nhiên, nó không được sử dụng như một không gian tên và nó chỉ trả về một số hàm trợ giúp chung; nó thiết lập cấu hình toàn cầu được sử dụng trên tất cả các nơi (Layout Manager và thư viện i18n bình thường). Trong một thế giới hoàn hảo, tôi sẽ không sử dụng 'module ứng dụng' và tôi đã thiết lập cấu hình thư viện bên trong' require.config', nhưng không may, RequireJS chỉ hỗ trợ 'init' cho các mô-đun shim. –

+1

Oh này, chỉ cần nhìn thấy những gì bạn có ý nghĩa. Không nhận ra dự án này đang sử dụng 'app' như một không gian tên. Tôi đã làm điều này trong quá khứ, nhưng tôi không còn như thế này là không đủ linh hoạt, vì vậy đây là một loại _relicat_. Nếu bạn tìm nơi 'instance/settings' được sử dụng, bạn sẽ thấy rằng nó chỉ sử dụng giá trị trả về, không phải là không gian tên. –

1

tôi sẽ xem xét ví dụ này repo https://github.com/tbranyen/github-viewer

Đây là một ví dụ làm việc về tấm nồi hơi xương sống (https://github.com/tbranyen/backbone-boilerplate)

Xương sống Nồi hơi có nhiều lông tơ không cần thiết, nhưng nó mang lại một số hướng rõ ràng về các mẫu chung để phát triển các ứng dụng javascript phức tạp.

tôi sẽ cố gắng và quay lại sau ngày hôm nay để trả lời bạn câu hỏi cụ thể hơn (nếu ai đó không đánh bại tôi vào nó :)

1

Tôi thích Giải pháp 1. Đó là nói chung tốt để avoidusingsingletons, và bằng cách sử dụng globals cũng là một cái gì đó để tránh, đặc biệt là kể từ khi bạn đang sử dụng RequireJS.

Dưới đây là một số lợi thế mà tôi có thể nghĩ đến cho Giải pháp 1:

Điều này làm cho mã xem dễ đọc hơn. Ai đó nhìn vào mô-đun lần đầu tiên có thể thấy ngay từ việc nhìn vào chức năng initialize mà các mô hình mà nó sử dụng. Nếu bạn sử dụng globals, một cái gì đó có thể được truy cập 500 dòng xuống trong tập tin.

Giúp dễ dàng viết các bài kiểm tra đơn vị cho mã chế độ xem. Vì bạn có thể có thể vượt qua trong các mô hình giả trong các bài kiểm tra của bạn.

+0

Điểm tuyệt vời. Cảm ơn. – Bart

+1

Tôi thực sự đồng ý với quan điểm của Paul. Sử dụng tùy chọn 1 cho phép bạn dễ dàng kiểm tra bất kỳ đối tượng liên quan Backbone nào và cho phép nó dễ đọc khi tất cả mã của bạn được chia thành nhiều mô-đun và đối tượng, v.v. Điểm tôi muốn thêm vào tùy chọn 1 là nó giúp thực thi mô hình pub/sub của xương sống. Sử dụng sự kiện điều khiển tốt hơn nhiều so với gọi hàm trực tiếp! – adrian

+1

Tôi không đồng ý về điểm dễ đọc của bạn. this.repoModel đang được đặt thành options.repoModel. Chúng tôi không có cách nào để biết những gì có trong các tùy chọn cũng như những gì options.repoModel là? Để tìm ra những gì có trong các tùy chọn và options.repoModel, chúng ta phải theo dõi mã đang khởi tạo mô-đun này. Tôi có thể được một chút về giả định này, nhưng kể từ khi bart được sử dụng yêu cầu, tại sao vượt qua xung quanh các mô-đun thông qua các chức năng? – andyzinsser

Các vấn đề liên quan