Tweak up AngularJS
Understanding data-binding and watchers Databinding là kỹ thuật dùng để tạo sự gắn kết giữa phần giao diện (UI) và dữ liệu thông qua phần business logic. Nhờ Databinding, UI có thể tự động cập nhật lại để hiển thị các thay đổi trong dữ liệu cũng như cập nhật từ UI vào dữ liệu. Để làm được điều ...
Understanding data-binding and watchers
Databinding là kỹ thuật dùng để tạo sự gắn kết giữa phần giao diện (UI) và dữ liệu thông qua phần business logic. Nhờ Databinding, UI có thể tự động cập nhật lại để hiển thị các thay đổi trong dữ liệu cũng như cập nhật từ UI vào dữ liệu. Để làm được điều đó, Angular sử dụng $$atch API để theo dõi sự thay đổi của model trên scope.
Nếu bạn không tạo ra một child scope bằng cách sử dụng ngController directive để tạo ra mối liên kết giữa DOM và controller thì một điều chắc chắn bạn đang làm việc với $rootScope - là scope gốc được sinh ra bởi Angular. Tuy nhiên, tại một thời điểm bất kì ta luôn luôn phải làm việc với một scope nào đó và nó được sử dụng để quan sát mọi sự thay đổi xảy ra trên chính bản thân nó - do đó được gọi là watcher. Các watchers được khai báo thông qua các directive được sử dụng trong DOM.
<p>Hello {{name}}!</p>
Ở ví dụ trên, directive đăng kí một watch cho thuộc tính name trong scope để hiện thị giá trị của nó trên DOM.
angular.module('myApp', []) .run(function ($rootScope) { $rootScope.name = "Picasso"; });
Giá trị của model name vừa được gắn với view dựa vào interpolation directive. Giờ đây nếu giá trị của name thay đổi, view sẽ được tự động cập nhật. Hãy thêm một button để thay đổi giá trị name mỗi khi nó được click.
<button ng-click="name = 'Da Vinci'">Click me!</button>
Click button sẽ gán giá trị mới 'Da Vinci' cho name, đồng thời sẽ kích hoạt một chu kì $$isgest theo đó cập nhật DOM. Trong trường hợp này, chúng ta chỉ cập nhật giá trị một chiều (top -> down), tuy nhiên, khi làm việc với các input được áp dụng directive, và người dùng nhập các giá trị tương ứng, mọi sự thay đổi sẽ được phản chiếu lại model thật.
Điều đó diễn ra là bởi khi disgest được kích hoạt, Angular sẽ đọc toàn bộ các watcher đã được khai báo ở scope hiện tại cũng như các child scope của nó và kiểm tra các sự thay đổi của model, cuối cùng gọi các callback tương ứng của watch cho đến khi model ổn định không còn thay đổi nào nữa. Một khi vòng digest kết thúc, trình duyệt sẽ re-render DOM với giá trị mới nhất.
Too many watchers
Angular thật là vi diệu, nhưng có thể dẫn đến vấn đề về performance khi kích thước của application tăng lên. Càng nhiều watch binding được khai báo, càng nhiều công việc AngularJS phải làm trong mỗi disgest. Việc giữ số lượng watcher dưới 2000 được cho là cần thiết để giảm thiểu tình trạng crash cũng như giữ cho performance ổn định. Tuy nhiên, liệu bạn có tự tin mình có khả năng nhận biết được thời điểm số lượng watcher chạm tới con số đó ? Xin giới thiệu với các bạn một extension khá hay dành cho Chrome có thể giúp dễ dàng theo dõi số lượng các watch, tạo tiền đề cho việc refactor code khi mà performance quá tệ.
Angular Watchers
Chúng ta sẽ sử dụng công cụ này để đánh giá hiệu quả của việc tweak AngularJS với việc sử dụng One-time binding dưới đây.
One-time binding
Đầu tiên, phải khẳng định đây không phải là one-way data-binding, thứ này không bao giờ tồn tại trong khuôn khổ của AngularJS. One-time binding cho phép một model hay view được cập nhật một lần duy nhất từ giá trị được set bởi controller trong vòng disgest đầu tiên. Do đó không cần thêm bất cứ watcher nào cần phải dùng cho thuộc tính đó để gắn vào view/model nữa. Ngay cả khi giá trị của thuộc tính bị thay đổi trong controller, nó cũng sẽ không được cập nhật dưới view.
One-time expressions will stop recalculating once they are stable, which happens after the first digest…
Để sử dụng one-time binding chúng ta chỉ cần soạn code với cú pháp: ::expression, ví dụ
<p>Hello {{name}}!</p>
thành
<p>Hello {{::name}}!</p>
So sánh số lượng watcher giữa 2 lần: Two way binding:
One time binding:
Số lượng watcher đã giảm đi sau khi sử dụng one time binding cũng như giá trị name không bao giờ thay đổi ngay cả khi button Click me! được click.
Câu hỏi đặt ra là khi nào sử dụng Two-Way và One-Time. Đó thực sự tùy thuộc vào tình huống bạn sử dụng. Nếu nó là một giá trị bạn dự định chỉ set trong vòng digest đầu tiên và sẽ không bao giờ thay đổi nó trên view, giả dụ tên, giá tiền của một sản phẩm trong product page hiển thị cho khách hàng, one-time là sự lựa chọn không thể tốt hơn. Nhưng ngược lại nếu đó là product page dành cho chủ shop bán hàng và họ có nhu cầu muốn cập nhật thay đổi giá cả thường xuyên, two-way nên được áp dụng. Lựa chọn đúng sẽ giúp bạn tiết kiệm được khá nhiều watcher cũng như tài nguyên đó!!!