2011-11-03 20 views
61

Tôi hiện đang làm việc trên một ứng dụng web lớn được xây dựng trên backbone.js và đã gặp rất nhiều vấn đề với tổ chức, "thây ma", v.v. vì vậy tôi đã quyết định thực hiện refactor chính của mã. Tôi đã viết một loạt các hàm trợ giúp để xử lý các "thây ma"; tuy nhiên, tôi muốn bắt đầu ngay từ đầu và tạo cấu trúc/tổ chức tốt đẹp cho mã. Tôi đã không tìm thấy nhiều hướng dẫn/ví dụ tuyệt vời về tổ chức backbone.js quy mô lớn vì vậy tôi đã bắt đầu từ đầu và muốn xem liệu tôi có thể nhận được một số ý kiến ​​về nơi tôi đã bắt đầu hay không.Tổ chức ứng dụng web backbone.js lớn

Tôi rõ ràng đã thiết lập mã của mình trong không gian tên chung; nhưng tôi cũng muốn giữ không gian tên đó khá sạch sẽ. Ứng dụng chính của tôi giữ cho các tệp lớp tự tách biệt khỏi không gian tên chung; bạn có thể đăng ký một lớp (để nó có thể được khởi tạo) bằng cách sử dụng hàm reg() và hàm inst() khởi tạo một lớp từ mảng lớp. Do đó, bên cạnh 3 phương pháp, không gian tên MyApp chỉ có Router, Model và View:

var MyApp = (function() { 

    var classes = { 
     Routers: {}, 
     Collections: {}, 
     Models: {}, 
     Views: {} 
    }; 

    methods = { 

     init: function() { 
      MyApp.Router = MyApp.inst('Routers', 'App'); 
      MyApp.Model = MyApp.inst('Models', 'App'); 
      MyApp.View = MyApp.inst('Views', 'App'); 
      Backbone.history.start(); 
     }, 

     reg: function (type, name, C) { 
      classes[type][name] = C; 
     }, 

     inst: function (type, C, attrs) { 
      return new classes[type][C](attrs || {}); 
     } 

    }; 

    return methods; 

}()); 

$(MyApp.init); 

Trong mô hình, bộ sưu tập, Router và xem, tôi làm việc như bình thường nhưng sau đó cần phải đăng ký lớp học mà ở phần cuối của tệp để nó có thể được khởi tạo tại một điểm sau đó (không làm lộn xộn không gian tên) với:

MyApp.reg('Models', 'App', Model); 

Đây có phải là cách không cần thiết để tổ chức mã không? Những người khác có ví dụ tốt hơn về cách tổ chức các dự án thực sự lớn với nhiều Bộ định tuyến, Bộ sưu tập, Mô hình và Chế độ xem không?

+0

lẽ http://codereview.stackexchange.com là phù hợp hơn cho các loại hình câu hỏi - nhưng giữ cho chúng tôi cập nhật (post link);) – sled

+0

Bạn có thể sắp mã của bạn trong mô-đun khác nhau. Bạn có thể xem https://github.com/juggy/backbone-module Tự quảng bá nhỏ: p – Julien

Trả lời

32

Gần đây tôi đã làm việc trên một dự án Backbone có tên là GapVis (code here, rendered content here). Tôi không biết nếu nó là "thực sự lớn", nhưng nó lớn và tương đối phức tạp - 24 lớp xem, 5 bộ định tuyến, vv Nó có thể đáng xem, mặc dù tôi không biết rằng tất cả các phương pháp tiếp cận của tôi sẽ liên quan, thích hợp. Bạn có thể thấy một số suy nghĩ của tôi trong nhận xét giới thiệu dài trong số main app.js file của tôi. Một vài lựa chọn kiến ​​trúc chính:

  • Tôi có một State mô hình singleton chứa tất cả thông tin tình trạng hiện thời - giao diện hiện tại, những gì ids mô hình chúng tôi đang tìm kiếm, vv Mỗi quan điểm cho rằng cần phải thay đổi trạng thái ứng dụng không bằng cách thiết lập các thuộc tính trên State và mọi chế độ xem cần phản hồi trạng thái lắng nghe mô hình đó cho các sự kiện. Điều này thậm chí còn đúng đối với các khung nhìn sửa đổi trạng thái và cập nhật - các trình xử lý sự kiện UI trong events không bao giờ trả lại khung nhìn, điều này được thực hiện thay vì thông qua các hàm kết xuất trả về cho trạng thái. Mẫu này thực sự giúp giữ cho các khung nhìn tách biệt với nhau - các khung nhìn không bao giờ gọi một phương thức trên một khung nhìn khác.

  • Bộ định tuyến của tôi được xem như chế độ xem chuyên dụng - chúng phản hồi sự kiện giao diện người dùng (tức là nhập URL) bằng cách cập nhật trạng thái và phản hồi thay đổi trạng thái bằng cách cập nhật giao diện người dùng (tức là thay đổi URL).

  • Tôi làm một số việc tương tự như những gì bạn đang đề xuất. Không gian tên của tôi có chức năng init tương tự như của bạn và đối tượng settings cho các hằng số. Nhưng tôi đặt hầu hết các mô hình và xem các lớp trong không gian tên là tốt, bởi vì tôi cần phải tham khảo chúng trong nhiều tập tin.

  • Tôi sử dụng hệ thống đăng ký cho các bộ định tuyến của mình và được xem là một trong các chế độ xem của tôi, như một cách hay để giữ các lớp "chính" (AppRouterAppView). Tuy nhiên, trong trường hợp AppView, hóa ra thứ tự quan điểm của trẻ là quan trọng, vì vậy tôi đã kết thúc việc mã hóa các lớp đó.

Tôi không thể nói rằng đây là cách "đúng" để làm mọi thứ, nhưng nó đã hiệu quả đối với tôi. Tôi hy vọng điều đó hữu ích - tôi cũng gặp khó khăn trong việc tìm kiếm các ví dụ nguồn có thể nhìn thấy của các dự án lớn bằng cách sử dụng Backbone, và phải tìm ra hầu hết những điều này khi tôi đi cùng.

+0

Cảm ơn tất cả thông tin đó; Tôi rất vui vì cả hai chúng tôi đều có những quy trình suy nghĩ tương tự - ít nhất nó cũng xác nhận rằng tôi không điên cuồng haha. Tôi chắc chắn thích ý tưởng của bạn về việc sử dụng các sự kiện thường xuyên hơn và sử dụng các bộ định tuyến đơn giản là "các chế độ xem url". Tôi đoán tôi vẫn chưa hoàn toàn chắc chắn liệu hệ thống đăng ký của mình cho tất cả các lớp có đáng giá hay không ... Nó không làm lộn xộn không gian tên chung nhưng điều đó có quan trọng không? Có vấn đề hiệu suất liên quan đến việc lộn xộn lên không gian tên MyApp với các tệp lớp? – user527480

+0

Tôi nghĩ rằng bạn có thể đã quá tải về phần đó, nếu mục tiêu chính của bạn là giữ cho không gian tên được sạch sẽ - không có bất kỳ vấn đề hiệu suất nào mà tôi biết, vấn đề là nhiều hơn về tổ chức mã. Có một số lợi ích nén khi sử dụng 'var MyClass' thay vì' ns.MyClass', thường không bị cắt xén, nhưng nó rất nhỏ và bạn vẫn sử dụng tên chuỗi. – nrabinowitz

5

tôi không gian tên tương tự như những gì bạn đang làm (ít nhất là cho các lớp học phần) và tất cả của tôi models, views, và bộ điều khiển giống như thế này:

views/blocks.js:

(function(cn){ 
    cn.classes.views.blocks = cn.classes.views.base.extend({ 

     events: {}, 

     blocksTemplate: cn.helpers.loadTemplate('tmpl_page_blocks'), 

     initialize: function(){ 
     }, 

     render: function(){ 
      $(this.el).html(this.blocksTemplate()); 
     }, 

     registerEvents: function(){}, 
     unregisterEvents: function(){} 
    }); 
})(companyname); 

namespace My JavaScript trông như thế này, mặc dù tôi cải tiến nó mỗi khi tôi xây dựng một ứng dụng mới:

companyname:{                                             
    $: function(){},  <== Shortcut reference to document.getElementById                              
    appView: {},   <== Reference to instantiated AppView class.                               
    classes = {   <== Namespace for all custom Backbone classes.                               
    views : {},                                             
    models : {},                                            
    collections: {},                                           
    controllers : {},                                           
    Router: null                                            
    },                                               
    models: {},   <== Instantiated models.                                     
    controllers: {},  <== Instantiated controllers.                                   
    router: {},   <== Instantiated routers.                                    
    helpers: {},   <== Reusable helper platform methods.                                 
    currentView: {},  <== A reference to the current view so that we can destroy it.                           
    init: function(){} <== Bootstrap code, starts the app.                               
} 

Bất cứ điều gì tôi muốn tất cả các quan điểm của tôi có, tôi đặt trong giao diện cơ bản. Bộ điều khiển của tôi sẽ gọi registerEvents trên bất kỳ chế độ xem mới nào mà nó tạo ra (sau khi hiển thị) và unregisterEvents trên chế độ xem ngay trước khi nó bị tiêu diệt. Không phải tất cả các khung nhìn đều có hai phương thức bổ sung này để nó đầu tiên kiểm tra sự tồn tại.

Đừng quên rằng tất cả chế độ xem đều được tích hợp sẵn this.el.remove();. Điều này không chỉ giết chết phần tử vùng chứa chế độ xem mà còn hủy liên kết tất cả các sự kiện được gắn với nó. Tùy thuộc vào cách bạn đang tạo quan điểm của bạn thông qua bộ điều khiển của bạn, bạn có thể không thực sự muốn giết nguyên tố và thực hiện điều này.el.unbind() để hủy bỏ tất cả các sự kiện.

+0

trong trường hợp nào tôi sẽ không muốn giết nguyên tố và làm this.el.unbind()? Tôi có một phương pháp đóng để thực hiện bước tiếp theo: nếu (this.onClose) this.onClose(); $ (this.el) .remove(); $ (this.el) .unbind(); – ccsakuweb

+2

'.remove' thực hiện' .unbind' tự động vì vậy bạn nên làm tốt. –

5

Trong thực tế, theo những cách khác nhau có những ưu và nhược điểm của cách khác nhau. Điều quan trọng nhất là tìm một cách phù hợp để tổ chức các tệp. Sau đây là tổ chức của dự án tôi hiện đang làm. Bằng cách này, tiêu điểm sẽ là các tập tin liên quan đến mô-đun tương tự được đặt trong một thư mục. Ví dụ: mô-đun người, mô-đun này tất cả các tệp được đặt trong thư mục modules/base/people. Sau khi cập nhật và bảo trì mô-đun này, chỉ cần tập trung vào các tệp trong thư mục này trên dòng, sẽ không ảnh hưởng đến tệp bên ngoài thư mục và cải thiện khả năng bảo trì.

Tôi hy vọng câu trả lời của tôi có thể cung cấp cho bạn một số trợ giúp, tôi hy vọng bạn có một số lời khuyên có giá trị.

enter image description here

+1

Tôi có một thư mục với các mô-đun quá nhưng tôi nghĩ rằng mỗi thư mục mô-đun cần thư mục mô hình và thư mục xem ít nhất – ccsakuweb

+0

context.js là gì? bạn có github không – alejandro