Backbone đầy rẫy những cái bẫy lớn

Backbone đầy rẫy những cái bẫy lớn

King88 Game Bài Club

Tổng kết thực chiến với Backbone

Ngày cập nhật: 12/12/2015 | Lượt đọc: 11986 | Phân loại: BackboneJS

Tìm kiếm

Trong vòng hai tuần vừa qua, tôi đã làm việc ở phần chuyển đổi tên miền về phía frontend. Để tương thích với code cũ, chúng tôi quyết định sử dụng Backbone. Quá trình trải nghiệm không hề dễ dàng, đi kèm với vô số lỗi và thử thách. Những ngày này, tôi thường xuyên phải làm việc quá giờ, thậm chí mơ mộng cũng chỉ xoay quanh logic render của frontend. Cảm giác gần như phát điên. Tuy nhiên, tôi cũng học được rất nhiều thứ, hiện tại khi viết frontend thì mình cảm thấy tự tin hơn rất nhiều.

Đây là lời than phiền hoàn toàn trung thực. Việc sử dụng một framework “nguyên thủy” như Backbone giúp rèn luyện rất tốt nền tảng JavaScript của lập trình viên.

Khối lượng code khổng lồ

Cảm giác như mình dùng Backbone mất cả tuần để xây dựng một chức năng mà nếu dùng Angular thì có thể hoàn thành trong hai ngày. Số dòng code không phải vấn đề lớn — nếu logic rõ ràng, code dài vẫn chấp nhận được. Tuy nhiên, Backbone lại khiến bạn phải viết rất nhiều code, logic phức tạp và khó kiểm soát.

Vấn đề về khối lượng code có thể giải quyết bằng các công cụ tự động hóa. Ví dụ như các plugin cho VIM, hoặc các đoạn mã khai báo Model, Collection, View nhanh chóng. Hiện tại tôi đang sử dụng plugin UltiSnips trên VIM để tăng tốc độ coding.

Sử dụng tên biến có ý nghĩa

Không nên dùng this.model, this.collection bên trong View. Khi nhiều View cùng lắng nghe một Model hoặc Collection, việc tìm kiếm code sẽ trở nên cực kỳ khó khăn, đặc biệt là khi cần xác định xem ai đang listen đến một Model nào đó.

Trường hợp 1: Nút nhấn không phản hồi do re-render làm mất binding sự kiện

Hiện tượng xảy ra khi View cha bị re-render (thực hiện this.$el.html(...) rồi append con view), dẫn đến nút nhấn của con view không hoạt động, tức là events không còn được bind.

Tham khảo bài viết: Backbone: event lost in re-render

Cơ chế hoạt động của Backbone khi render:

1
2
this.$el.empty();
this.$el.append(this.subView.render().el);

Phương thức .empty() của jQuery sẽ xóa sạch tất cả các sự kiện gắn liền với element đó. Cách khắc phục là chủ động gọi lại phương thức delegateEvents() của subView sau khi render.

1
2
3
4
5
render: function(){
  this.$el.html( this.subView.render().el );       
  this.subView.delegateEvents();
  return this;
}

Theo tài liệu chính thức, delegateEvents() sẽ được gọi một lần duy nhất khi View được khởi tạo, xử lý các sự kiện trong phần events. Trong quá trình re-render, các sự kiện này bị xóa đi, vì vậy ta cần gọi lại delegateEvents() để đảm bảo sự kiện được gắn lại.

Trường hợp 2: Sự kiện không hoạt động do mất điểm mount khi switch view

Cấu trúc logic giao diện:

1
2
3
4
5
6
TRANG CHỦ
|_ View 1
|_ View 2
   |_ View 2.1
   |_ View 2.2
   |_ View 2.3

Hiện tượng: Khi từ View 2.1 trở lại View 1, sau đó quay lại View 2.1 ~ 2.3, giao diện không refresh nhưng request AJAX trong initialize vẫn chạy. Điều này cho thấy render không được gọi lại, nhưng initialize thì vẫn chạy.

Nguyên nhân: View 2.1 ~ 2.3 được gắn vào View 2. Khi chuyển sang View 1, View 2 bị xóa (this.$el.empty()). Khi quay lại View 2.1 ~ 2.3, View 2 không được render lại, dẫn đến giao diện không hiển thị.

Giải pháp: Mỗi lần quay lại View 2.1 ~ 2.3, hãy chắc chắn rằng View 2 được render lại đầy đủ.

Dù là giao diện đơn giản, cũng nên áp dụng mô hình Model/View

Dù là một trang web nhỏ hay phức tạp, việc sử dụng mô hình Model/View luôn là cách tối ưu. Hãy lắng nghe sự thay đổi của Model và re-render View khi cần thiết. Đây mới là cách tiếp cận đúng đắn và bền vững trong phát triển ứng dụng dựa trên Backbone.

Built with Hugo
Theme Stack thiết kế bởi Jimmy