Câu hỏi Làm thế nào để làm việc dữ liệu ràng buộc trong AngularJS?


Tính năng ràng buộc dữ liệu hoạt động như thế nào trong AngularJS khuôn khổ?

Tôi chưa tìm thấy chi tiết kỹ thuật trang web của họ. Nó ít nhiều rõ ràng cách nó hoạt động khi dữ liệu được truyền từ dạng xem sang mô hình. Nhưng làm thế nào để AngularJS theo dõi các thay đổi của các thuộc tính mô hình mà không cần các bộ định tuyến và getters?

Tôi thấy rằng có Trình theo dõi JavaScript có thể thực hiện công việc này. Nhưng chúng không được hỗ trợ Internet Explorer 6 và Internet Explorer 7. Vậy AngularJS biết rằng tôi đã thay đổi như thế nào sau đây và phản ánh sự thay đổi này trên một khung nhìn?

myobject.myproperty="new value";

1803
2018-03-13 10:16


gốc


Lưu ý rằng kể từ khi 1.0.0rc1 góc, bạn cần chỉ định ng-model-instant (docs-next.angularjs.org/api/…) để người kiểm duyệt của bạn được cập nhật một cách nhanh chóng. Nếu không nó sẽ được cập nhật trên sự kiện mờ. - Sotomajor
Liên kết của Marcello dường như bị hỏng, vì vậy ở đây nó lại một lần nữa: github.com/mhevery/angular.js/blob/master/docs/content/guide/… - riffraff
@orian, liên kết đó là xấu. cập nhật thành (tôi giả định) là như nhau - docs.angularjs.org/guide/databinding - Kevin Meredith
Đối với những người vẫn đọc câu hỏi này, xin lưu ý rằng Angular 2.0 đã thay đổi rất nhiều cách họ đi về databinding kể từ Angular 1.x để làm việc với các thành phần web và giải quyết rất nhiều vấn đề trong các câu trả lời dưới đây. - aug


Các câu trả lời:


AngularJS nhớ giá trị và so sánh nó với giá trị trước đó. Đây là kiểm tra bẩn cơ bản. Nếu có thay đổi về giá trị, thì nó sẽ kích hoạt sự kiện thay đổi.

Các $apply() phương pháp, đó là những gì bạn gọi khi bạn đang chuyển từ một thế giới không AngularJS thành một thế giới AngularJS, các cuộc gọi $digest(). Một thông báo chỉ là đồng bằng cũ bẩn kiểm tra. Nó hoạt động trên tất cả các trình duyệt và hoàn toàn có thể dự đoán được.

Để tương phản kiểm tra bẩn (AngularJS) so với người nghe thay đổi (KnockoutJS và Backbone.jsTrong khi kiểm tra bẩn có vẻ đơn giản, và thậm chí không hiệu quả (tôi sẽ giải quyết sau), nó chỉ ra rằng nó là ngữ nghĩa chính xác mọi lúc, trong khi người nghe thay đổi có nhiều trường hợp góc kỳ lạ và cần những thứ như theo dõi phụ thuộc để thực hiện nó đúng ngữ nghĩa hơn. Theo dõi phụ thuộc KnockoutJS là một tính năng thông minh cho một vấn đề mà AngularJS không có.

Các vấn đề với người nghe thay đổi:

  • Cú pháp là khủng khiếp, vì các trình duyệt không hỗ trợ nó một cách tự nhiên. Có, có proxy, nhưng chúng không đúng về mặt ngữ nghĩa trong mọi trường hợp, và tất nhiên là không có proxy trên các trình duyệt cũ. Điểm mấu chốt là kiểm tra bẩn cho phép bạn làm POJO, trong khi KnockoutJS và Backbone.js buộc bạn phải kế thừa từ các lớp của họ và truy cập dữ liệu của bạn thông qua các trình truy cập.
  • Thay đổi sự kết hợp. Giả sử bạn có một mảng các mục. Giả sử bạn muốn thêm các mục vào một mảng, vì bạn đang lặp để thêm, mỗi lần bạn thêm bạn sẽ kích hoạt các sự kiện khi thay đổi, sẽ hiển thị giao diện người dùng. Điều này là rất xấu cho hiệu suất. Những gì bạn muốn là cập nhật giao diện người dùng chỉ một lần, ở cuối. Sự kiện thay đổi quá chi tiết.
  • Thay đổi người nghe bắn ngay lập tức trên một setter, đó là một vấn đề, kể từ khi người nghe thay đổi có thể thay đổi dữ liệu hơn nữa, mà cháy nhiều sự kiện thay đổi. Điều này là xấu kể từ trên stack của bạn, bạn có thể có một số sự kiện thay đổi xảy ra cùng một lúc. Giả sử bạn có hai mảng cần được giữ đồng bộ vì bất kỳ lý do gì. Bạn chỉ có thể thêm vào một hoặc cái khác, nhưng mỗi khi bạn thêm bạn kích hoạt sự kiện thay đổi, sự kiện hiện có chế độ xem không nhất quán của thế giới. Đây là một vấn đề rất giống với khóa luồng, mà JavaScript tránh vì mỗi lần gọi lại thực hiện độc quyền và hoàn thành. Sự kiện thay đổi phá vỡ điều này kể từ khi setters có thể có hậu quả sâu rộng mà không phải là dự định và không rõ ràng, mà tạo ra các vấn đề thread trên một lần nữa. Nó chỉ ra rằng những gì bạn muốn làm là trì hoãn việc lắng nghe người nghe và đảm bảo rằng chỉ có một người nghe chạy cùng một lúc, do đó bất kỳ mã nào đều miễn phí để thay đổi dữ liệu và nó biết rằng không có mã nào khác chạy trong khi nó đang làm như vậy .

Điều gì về hiệu suất?

Vì vậy, có vẻ như chúng tôi đang chậm, kể từ khi kiểm tra bẩn là không hiệu quả. Đây là nơi chúng ta cần xem xét các số thực thay vì chỉ có các đối số lý thuyết, nhưng trước tiên chúng ta hãy định nghĩa một số ràng buộc.

Con người là:

  • Chậm - Bất cứ điều gì nhanh hơn 50 ms là không thể nhận ra với con người và do đó có thể được coi là "ngay lập tức".

  • Giới hạn - Bạn không thể hiển thị hơn 2000 mẩu thông tin cho một người trên một trang. Bất cứ điều gì nhiều hơn đó thực sự là giao diện người dùng xấu, và con người không thể xử lý này anyway.

Vì vậy, câu hỏi thực sự là: Bạn có thể so sánh bao nhiêu lần so với trình duyệt trong 50 ms? Đây là một câu hỏi khó trả lời khi có nhiều yếu tố đi vào hoạt động, nhưng đây là một trường hợp thử nghiệm: http://jsperf.com/angularjs-digest/6 tạo 10.000 người theo dõi. Trên trình duyệt hiện đại, việc này chỉ mất dưới 6 phút. Trên Internet Explorer 8 nó mất khoảng 40 ms. Như bạn có thể thấy, đây không phải là vấn đề ngay cả trên các trình duyệt chậm trong những ngày này. Có một sự báo trước: Các so sánh cần phải đơn giản để phù hợp với giới hạn thời gian ... Thật không may là quá dễ dàng để thêm một so sánh chậm vào AngularJS, do đó rất dễ dàng để xây dựng các ứng dụng chậm khi bạn không biết bạn đang làm. Nhưng chúng tôi hy vọng sẽ có một câu trả lời bằng cách cung cấp một mô-đun thiết bị đo đạc, mà sẽ cho bạn thấy đó là những so sánh chậm.

Nó chỉ ra rằng trò chơi video và GPU sử dụng phương pháp kiểm tra bẩn, đặc biệt bởi vì nó là phù hợp. Miễn là chúng vượt qua tốc độ làm tươi màn hình (thường là 50-60 Hz, hay 16,6-20 ms), bất kỳ hiệu suất nào trên đó đều là một sự lãng phí, vì vậy bạn nên giảm nhiều thứ hơn là tăng FPS.


2660
2018-03-13 23:47



@Mark - vâng, trong KO bạn chỉ cần thêm .extend ({throttle: 500}) để chờ 500 mili giây sau sự kiện thay đổi cuối cùng trước khi hành động trên nó. - Daniel Earwicker
Câu trả lời này hoàn toàn khác với "Miễn là họ nhận được 50 khung hình / giây, bất kỳ hiệu suất nào trên đó là một sự lãng phí, vì mắt người không thể đánh giá cao nó, vì vậy bạn nên vẽ nhiều thứ hơn là tăng fps." Tuyên bố đó hoàn toàn không chính xác tùy thuộc vào ứng dụng của bạn. Con mắt chắc chắn có thể đánh giá cao hơn 50 khung hình / giây, và như các vấn đề khác nhau với chương trình VR (đọc bất kỳ mới nhất từ ​​John Carmack hoặc Michael Abrash, đặc biệt là nói chuyện GDC 2013 VR), 50 fps thực sự là quá chậm. Khác hơn thế, câu trả lời của bạn là tuyệt vời. Tôi chỉ không muốn thông tin sai lạc lan rộng. - Nate Bundy
Chỉ cần tự hỏi, nếu ứng dụng của bạn giống như Twitter hoặc chuỗi nhận xét / diễn đàn và bạn triển khai cuộn vô hạn dựa trên Angular, bạn có thể chạy vào "2000 mẩu thông tin" "giới hạn". Một bình luận đơn giản có thể dễ dàng có nhiều biến cho tên tác giả, img, nội dung, datetime và vv. Ngoài ra, chúng ta có một mảng khổng lồ để lưu trữ tất cả các bình luận / bài viết, mọi kiểm tra bẩn sẽ yêu cầu quét mảng này, Tôi đúng? Điều này sẽ làm cho trình duyệt hơi khó khăn vào những thời điểm mà đó là trải nghiệm người dùng kém. Bạn đề nghị chúng tôi làm gì trong trường hợp này để đảm bảo hiệu suất hợp lý? - Lucas
Tuyên bố có thể dễ dàng nói ngược lại là "Kiểm tra bẩn là một tính năng thông minh cho một vấn đề mà loại trực tiếp không có". ES6 đang sử dụng các quan sát và góc cạnh là loại bỏ việc kiểm tra bẩn. Thế giới thực bắt kịp câu trả lời này và cho thấy nó là sai. - conical
"Bất cứ điều gì nhanh hơn 50 ms là không thể nhận ra với con người" là không đúng sự thật. Trong thử nghiệm, chúng tôi đã tìm thấy khách hàng của chúng tôi có thể dễ dàng phân biệt độ trễ cập nhật 50ms (20fps) và độ trễ cập nhật 16,6ms (60 khung hình / giây). Các cảnh chạy ở tốc độ cũ luôn nhận được xếp hạng tổng thể kém hơn "cảm giác như thế nào" ngay cả khi mọi người không có ý thức đăng ký tốc độ khung hình. - Crashworks


Misko đã đưa ra một mô tả tuyệt vời về cách các kết buộc dữ liệu hoạt động, nhưng tôi muốn thêm quan điểm của mình về vấn đề hiệu năng với ràng buộc dữ liệu.

Như Misko đã nói, khoảng 2000 ràng buộc là nơi bạn bắt đầu thấy vấn đề, nhưng bạn không nên có hơn 2000 mẩu thông tin trên một trang nào. Điều này có thể đúng, nhưng không phải mọi ràng buộc dữ liệu đều hiển thị với người dùng. Khi bạn bắt đầu xây dựng bất kỳ loại tiện ích hoặc lưới dữ liệu nào có liên kết hai chiều, bạn có thể dễ dàng nhấn 2000 ràng buộc, mà không có một ux xấu.

Hãy xem xét, ví dụ, một combobox, nơi bạn có thể gõ văn bản để lọc các tùy chọn có sẵn. Loại kiểm soát này có thể có ~ 150 mục và vẫn có thể sử dụng được. Nếu nó có một số tính năng bổ sung (ví dụ một lớp cụ thể trên tùy chọn hiện đang được chọn), bạn bắt đầu nhận được 3-5 liên kết cho mỗi tùy chọn. Đặt ba trong số các tiện ích này trên một trang (ví dụ: một để chọn quốc gia, một để chọn thành phố ở quốc gia được nói và thứ ba để chọn khách sạn) và bạn đã ở đâu đó từ 1000 đến 2000 liên kết rồi.

Hoặc xem xét một lưới dữ liệu trong một ứng dụng web của công ty. 50 hàng trên mỗi trang không phải là không hợp lý, mỗi hàng trong số đó có thể có 10-20 cột. Nếu bạn xây dựng này với ng-lặp lại, và / hoặc có thông tin trong một số tế bào trong đó sử dụng một số ràng buộc, bạn có thể được tiếp cận 2000 bindings với lưới này một mình.

Tôi thấy đây là một khổng lồ vấn đề khi làm việc với AngularJS và giải pháp duy nhất mà tôi có thể tìm thấy là xây dựng các widget mà không cần sử dụng liên kết hai chiều, thay vào đó sử dụng ngOnce, các trình theo dõi đăng ký và các thủ thuật tương tự, hoặc xây dựng các chỉ thị xây dựng DOM với jQuery và Thao tác DOM. Tôi cảm thấy điều này đánh bại mục đích sử dụng Angular ngay từ đầu.

Tôi rất thích nghe những gợi ý về những cách khác để giải quyết vấn đề này, nhưng có lẽ tôi nên viết câu hỏi của riêng mình. Tôi muốn nói điều này trong một bình luận, nhưng hóa ra là quá lâu rồi ...

TL; DR 
Ràng buộc dữ liệu có thể gây ra các vấn đề hiệu suất trên các trang phức tạp.


308
2017-08-22 13:28



Vâng tôi thứ hai này. Trách nhiệm chính của ứng dụng của chúng tôi là hiển thị các kết nối giữa các thực thể khác nhau. Một trang nhất định có thể có 10 phần. Mỗi phần có một bảng. Mỗi bảng có 2-5 bộ lọc typeahead. Mỗi bảng có 2-5 cột, mỗi cột có 10 hàng. Rất nhanh chóng chúng tôi chạy vào các vấn đề về sự hoàn hảo và đi theo các tùy chọn "các mẹo tương tự". - Scott Silvi
Có công bằng khi nói rằng Góc không chỉ liên quan đến ràng buộc dữ liệu và một số ứng dụng có thể không muốn sử dụng tính năng này cho chính xác những lý do mà những người khác đã trích dẫn? Tôi nghĩ rằng cách tiếp cận của DI và mô đun là chính nó có giá trị rất nhiều; có ma thuật tự động ràng buộc là tốt đẹp, nhưng trong mỗi thực hiện hiện tại có thương mại-off hiệu suất. Cách của Angular được cho là vượt trội so với phần lớn các ứng dụng web CRUD, và mọi người chỉ đánh một bức tường bằng cách cố gắng đưa nó đến cực đoan. Nó sẽ là tốt đẹp để có một phương pháp thay thế của sự kiện nghe hỗ trợ, nhưng có lẽ đó là cơ bản quá phức tạp cho một khuôn khổ duy nhất? - Jason Boyd
Góc bây giờ có một cách và ràng buộc một lần databinding để giúp đỡ với vấn đề này. Hơn nữa nó bây giờ có chỉ số cho nguồn lặp của bạn, cho phép bạn sửa đổi danh sách mà không cần xây dựng lại dom cho toàn bộ nội dung. - Mithon
@MW. Thành thật mà nói, tôi nghĩ ràng buộc một lần là cốt lõi. Nhưng có vẻ như không. Nó chỉ là một cái gì đó bạn có thể làm khi viết chỉ thị của riêng bạn, về cơ bản liên kết công cụ mà không cần xem chúng. Tuy nhiên có một mod ux cho nó: github.com/pasvaz/bindonce - Mithon
Một tiếng hét từ tương lai cho bất cứ ai đọc điều này: một thời gian ràng buộc bây giờ là một tính năng cốt lõi trong Angular v1.3, đọc thêm ở đây: docs.angularjs.org/guide/expression - Nobita


Bằng cách kiểm tra bẩn $scope vật

Góc duy trì một đơn giản array người theo dõi trong $scope các đối tượng. Nếu bạn kiểm tra bất kỳ $scope bạn sẽ thấy rằng nó chứa một array gọi là $$watchers.

Mỗi người theo dõi là một object chứa trong số những thứ khác

  1. Một biểu thức mà người quan sát đang theo dõi. Đây có thể chỉ là một attribute tên, hoặc một cái gì đó phức tạp hơn.
  2. Giá trị được biết cuối cùng của biểu thức. Điều này có thể được kiểm tra so với giá trị tính toán hiện tại của biểu thức. Nếu các giá trị khác nhau, trình xem sẽ kích hoạt hàm và đánh dấu $scope bẩn.
  3. Một chức năng sẽ được thực hiện nếu người quan sát bị bẩn.

Cách người xem được xác định

Có nhiều cách khác nhau để xác định người quan sát trong AngularJS.

  • Bạn có thể rõ ràng $watch một attribute trên $scope.

    $scope.$watch('person.username', validateUnique);
    
  • Bạn có thể đặt một {{}} nội suy trong mẫu của bạn (người xem sẽ được tạo cho bạn trên hiện tại $scope).

    <p>username: {{person.username}}</p>
    
  • Bạn có thể yêu cầu một chỉ thị như ng-model để xác định người quan sát cho bạn.

    <input ng-model="person.username" />
    

Các $digest chu kỳ kiểm tra tất cả người theo dõi so với giá trị cuối cùng của họ

Khi chúng ta tương tác với AngularJS thông qua các kênh thông thường (ng-mô hình, ng-lặp lại, vv) một chu trình tiêu hóa sẽ được kích hoạt bởi chỉ thị.

Chu trình tiêu hóa là chiều ngang đầu tiên của $scope và tất cả các con của nó. Cho mỗi $scope  object, chúng tôi lặp lại $$watchers  array và đánh giá tất cả các biểu thức. Nếu giá trị biểu thức mới khác với giá trị đã biết cuối cùng, hàm của trình theo dõi được gọi. Hàm này có thể biên dịch lại một phần của DOM, tính toán lại giá trị trên $scope, kích hoạt một AJAX  request, bất cứ điều gì bạn cần nó để làm.

Mỗi phạm vi được duyệt qua và mọi biểu thức đồng hồ được đánh giá và kiểm tra dựa trên giá trị cuối cùng.

Nếu người quan sát được kích hoạt, $scope bẩn

Nếu người xem được kích hoạt, ứng dụng sẽ biết điều gì đó đã thay đổi và $scope được đánh dấu là bẩn.

Chức năng của trình theo dõi có thể thay đổi các thuộc tính khác trên $scope hoặc trên một phụ huynh $scope. Nếu một $watcher chức năng đã được kích hoạt, chúng tôi không thể đảm bảo rằng chức năng khác của chúng tôi $scopes vẫn sạch, và vì vậy chúng tôi thực hiện lại toàn bộ chu trình phân hủy.

Điều này là do AngularJS có liên kết hai chiều, vì vậy dữ liệu có thể được truyền lại $scopecây. Chúng tôi có thể thay đổi giá trị ở mức cao hơn $scope đã được tiêu hóa. Có lẽ chúng ta thay đổi một giá trị trên $rootScope.

Nếu $digest là bẩn, chúng tôi thực hiện toàn bộ $digest chu kỳ một lần nữa

Chúng tôi liên tục lặp qua $digest chu kỳ cho đến khi chu trình tiêu hóa trở nên sạch sẽ (tất cả $watch các biểu thức có cùng giá trị như chúng có trong chu kỳ trước) hoặc chúng tôi đạt đến giới hạn tiêu hóa. Theo mặc định, giới hạn này được đặt ở mức 10.

Nếu chúng ta đạt đến giới hạn tiêu hóa AngularJS sẽ gây ra lỗi trong bảng điều khiển:

10 $digest() iterations reached. Aborting!

Tiêu hóa khó trên máy nhưng dễ dàng trên nhà phát triển

Như bạn có thể thấy, mỗi khi có điều gì đó thay đổi trong ứng dụng AngularJS, AngularJS sẽ kiểm tra mọi người theo dõi trong $scope phân cấp để xem cách trả lời. Đối với một nhà phát triển, đây là một lợi ích năng suất lớn, vì bây giờ bạn cần phải viết hầu như không có mã dây, AngularJS sẽ chỉ thông báo nếu một giá trị đã thay đổi và làm cho phần còn lại của ứng dụng phù hợp với thay đổi.

Từ quan điểm của máy mặc dù điều này là cực kỳ không hiệu quả và sẽ làm chậm ứng dụng của chúng tôi xuống nếu chúng ta tạo quá nhiều người theo dõi. Misko đã trích dẫn một con số khoảng 4000 người xem trước khi ứng dụng của bạn sẽ cảm thấy chậm trên các trình duyệt cũ hơn.

Giới hạn này rất dễ tiếp cận nếu bạn ng-repeat trên một lớn JSON  array ví dụ. Bạn có thể giảm thiểu điều này bằng cách sử dụng các tính năng như ràng buộc một lần để biên dịch mẫu mà không cần tạo trình theo dõi.

Cách tránh tạo quá nhiều người theo dõi

Mỗi lần người dùng tương tác với ứng dụng của bạn, mọi người theo dõi trong ứng dụng của bạn sẽ được đánh giá ít nhất một lần. Một phần lớn trong việc tối ưu hóa ứng dụng AngularJS là giảm số người theo dõi trong $scope cây. Một cách dễ dàng để thực hiện điều này là một thời gian ràng buộc.

Nếu bạn có dữ liệu hiếm khi thay đổi, bạn có thể liên kết nó chỉ một lần bằng cú pháp :: như sau:

<p>{{::person.username}}</p>

hoặc là

<p ng-bind="::person.username"></p>

Việc ràng buộc sẽ chỉ được kích hoạt khi mẫu có chứa được hiển thị và dữ liệu được nạp vào $scope.

Điều này đặc biệt quan trọng khi bạn có ng-repeat với nhiều mặt hàng.

<div ng-repeat="person in people track by username">
  {{::person.username}}
</div>

142
2018-06-02 12:31



Tôi không đồng ý rằng câu trả lời nên ở trên cùng; có sự khác biệt giữa việc biết điều gì đó và viết câu trả lời có liên quan / chi tiết cho một câu hỏi cụ thể. Có những cách tốt hơn để nhận giải thưởng. Dù sao .. - user2864740
Tôi không nghi ngờ điều đó là đúng, nhưng đặt câu hỏi và trả lời câu trả lời :) - user2864740
Câu trả lời hay bao gồm cách kiểm tra hành vi bẩn và những gì nó thực sự đánh giá, một điều không quá rõ ràng trong câu trả lời của Misko. - bitstrider
Câu trả lời tuyệt vời và chi tiết. @superluminary, cảm ơn câu trả lời như vậy. Hơn nữa, sau khi đọc câu trả lời này, tôi đến điểm mà chúng ta không được thêm vào biểu thức không phải là một biểu tượng không cần thiết như một biểu thức đang được theo dõi. - Mangu Singh Rajpurohit
Đây sẽ là câu trả lời hàng đầu - Alexandre Bourlier


Đây là sự hiểu biết cơ bản của tôi. Nó cũng có thể sai!

  1. Các mục được theo dõi bằng cách truyền một hàm (trả về điều cần đã theo dõi) đến $watch phương pháp.
  2. Các thay đổi đối với các mục đã xem phải được thực hiện trong một khối mã bọc bởi $apply phương pháp.
  3. Vào cuối của $apply các $digest phương thức được gọi đi thông qua từng đồng hồ và kiểm tra để xem liệu họ đã thay đổi từ lần cuối $digest chạy.
  4. Nếu bất kỳ thay đổi nào được tìm thấy thì thông báo được gọi lại cho đến khi tất cả các thay đổi đều ổn định.

Trong phát triển bình thường, cú pháp ràng buộc dữ liệu trong HTML cho trình biên dịch AngularJS tạo đồng hồ cho bạn và các phương thức điều khiển được chạy bên trong $apply rồi. Vì vậy, để các nhà phát triển ứng dụng đó là tất cả minh bạch.


77
2018-03-13 21:01



khi nào phương pháp áp dụng được kích hoạt? - numan salati
@EliseuMonar Vòng lặp digest chạy như một kết quả của một số sự kiện hoặc gọi $ apply (), nó không được gọi định kỳ dựa trên một bộ đếm thời gian. xem Chức năng đồng hồ $ của AngularJS hoạt động như thế nào? và làm thế nào để công việc ràng buộc và tiêu hóa trong AngularJS? - remi
@remi, tôi không quan tâm đến phiên bản cuối cùng của AngularJS. Họ đã sử dụng proxy hay Object.observe chưa? Nếu không, chúng vẫn đang trong giai đoạn kiểm tra bẩn, xây dựng một vòng lặp theo thời gian để xem các thuộc tính mô hình có thay đổi hay không. - Eliseu Monar dos Santos
Tôi đã đọc thông báo đó sẽ chạy tối đa mười lần sitepoint.com/understanding-angulars-apply-digest - user137717


Tôi tự hỏi điều này một lúc. Không có người định cư như thế nào AngularJS thay đổi thông báo cho $scope vật? Liệu nó thăm dò ý kiến ​​họ?

Những gì nó thực sự làm được điều này: Bất kỳ "bình thường" nơi bạn sửa đổi các mô hình đã được gọi là từ ruột của AngularJS, do đó, nó sẽ tự động gọi $apply cho bạn sau khi mã của bạn chạy. Giả sử bộ điều khiển của bạn có phương thức được kết nối với ng-click trên một số yếu tố. Bởi vì AngularJS dây gọi điện thoại của phương pháp đó với nhau cho bạn, nó có một cơ hội để làm một $apply ở nơi thích hợp. Tương tự, đối với các biểu thức xuất hiện ngay trong các khung nhìn, các biểu thức được thực hiện bởi AngularJS do đó, nó $apply.

Khi tài liệu nói về việc phải gọi $apply thủ công cho mã bên ngoài của AngularJS, nó nói về mã, khi chạy, không xuất phát từ AngularJS chính nó trong ngăn xếp cuộc gọi.


57
2017-09-03 17:45





Giải thích bằng Ảnh:

Data-Binding cần một ánh xạ

Tham chiếu trong phạm vi không chính xác là tham chiếu trong mẫu. Khi bạn liên kết dữ liệu với hai đối tượng, bạn cần một đối tượng thứ ba lắng nghe đầu tiên và sửa đổi đối tượng kia.

enter image description here

Ở đây, khi bạn sửa đổi <input>, bạn chạm vào data-ref3. Và mecanism liên kết dữ liệu cổ điển sẽ thay đổi data-ref4. Vậy cách khác {{data}} biểu thức sẽ di chuyển?

Sự kiện dẫn đến $ digest ()

enter image description here

Góc duy trì một oldValue và newValue của mọi ràng buộc. Và sau mỗi Sự kiện góc, sự nổi tiếng $digest() vòng lặp sẽ kiểm tra Danh sách theo dõi để xem có thay đổi gì không. Những Sự kiện góc là ng-click, ng-change, $http hoàn thành $digest() sẽ lặp lại miễn là oldValue khác với newValue.

Trong hình trước, nó sẽ thông báo rằng data-ref1 và data-ref2 đã thay đổi.

Kết luận

Nó giống như trứng và gà. Bạn không bao giờ biết ai bắt đầu, nhưng hy vọng nó hoạt động phần lớn thời gian như mong đợi.

Điểm khác là bạn có thể hiểu dễ dàng tác động sâu sắc của một ràng buộc đơn giản trên bộ nhớ và CPU. Hy vọng rằng Máy tính để bàn đủ béo để xử lý việc này. Điện thoại di động không mạnh lắm.


29
2018-05-20 13:33





Rõ ràng không có kiểm tra định kỳ Scope cho dù có bất kỳ thay đổi nào trong các đối tượng gắn liền với nó hay không. Không phải tất cả các đối tượng gắn liền với phạm vi đều được xem. Phạm vi prototypically duy trì một $$ người theo dõi . Scope chỉ lặp lại thông qua điều này $$watchers khi nào $digest được gọi là .

Angular thêm người theo dõi vào $$ người theo dõi cho mỗi người trong số này

  1. {{expression}} - Trong các mẫu của bạn (và bất kỳ nơi nào khác có biểu thức) hoặc khi chúng tôi xác định mô hình ng.
  2. $ scope. $ watch (‘expression / function’) - Trong JavaScript của bạn, chúng tôi chỉ có thể đính kèm một đối tượng phạm vi cho góc để xem.

$ xem chức năng có ba tham số:

  1. Đầu tiên là một chức năng watcher mà chỉ trả về đối tượng hoặc chúng ta chỉ có thể thêm một biểu thức.

  2. Thứ hai là một hàm listener sẽ được gọi khi có sự thay đổi trong đối tượng. Tất cả những thứ như thay đổi DOM sẽ được thực hiện trong chức năng này.

  3. Thứ ba là một tham số tùy chọn có trong boolean. Nếu đúng, góc nhìn sâu của nó đối tượng và nếu Angular giả của nó chỉ làm một tham chiếu xem trên đối tượng.     Triển khai Rough của $ watch trông giống như thế này

Scope.prototype.$watch = function(watchFn, listenerFn) {
   var watcher = {
       watchFn: watchFn,
       listenerFn: listenerFn || function() { },
       last: initWatchVal  // initWatchVal is typically undefined
   };
   this.$$watchers.push(watcher); // pushing the Watcher Object to Watchers  
};

Có một điều thú vị trong Angular gọi là Digest Cycle. Chu kỳ $ digest bắt đầu từ một cuộc gọi đến $ scope. $ Digest (). Giả sử rằng bạn thay đổi mô hình $ scope trong một hàm xử lý thông qua chỉ thị ng-click. Trong trường hợp đó, AngularJS tự động kích hoạt chu trình $ digest bằng cách gọi $ digest () Ngoài ng-click, còn có một số chỉ thị / dịch vụ tích hợp khác cho phép bạn thay đổi các mô hình (ví dụ: ng-model, $ timeout, vv) và tự động kích hoạt chu kỳ tiêu hóa $. Việc thực hiện thô của $ digest trông như thế này.

Scope.prototype.$digest = function() {
      var dirty;
      do {
          dirty = this.$$digestOnce();
      } while (dirty);
}
Scope.prototype.$$digestOnce = function() {
   var self = this;
   var newValue, oldValue, dirty;
   _.forEach(this.$$watchers, function(watcher) {
          newValue = watcher.watchFn(self);
          oldValue = watcher.last;   // It just remembers the last value for dirty checking
          if (newValue !== oldValue) { //Dirty checking of References 
   // For Deep checking the object , code of Value     
   // based checking of Object should be implemented here
             watcher.last = newValue;
             watcher.listenerFn(newValue,
                  (oldValue === initWatchVal ? newValue : oldValue),
                   self);
          dirty = true;
          }
     });
   return dirty;
 };

Nếu chúng tôi sử dụng JavaScript setTimeout () chức năng để cập nhật một mô hình phạm vi, Angular không có cách nào để biết những gì bạn có thể thay đổi. Trong trường hợp này, trách nhiệm của chúng tôi là gọi $ apply () theo cách thủ công, kích hoạt chu kỳ $ digest. Tương tự, nếu bạn có chỉ thị thiết lập trình xử lý sự kiện DOM và thay đổi một số mô hình bên trong hàm xử lý, bạn cần gọi $ apply () để đảm bảo các thay đổi có hiệu lực. Ý tưởng lớn của $ áp dụng là chúng ta có thể thực thi một số mã không nhận thức được Angular, mã đó vẫn có thể thay đổi mọi thứ trên phạm vi. Nếu chúng ta bọc mã đó trong $ apply, nó sẽ chăm sóc gọi $ digest (). Triển khai thô của $ apply ().

Scope.prototype.$apply = function(expr) {
       try {
         return this.$eval(expr); //Evaluating code in the context of Scope
       } finally {
         this.$digest();
       }
};

19
2018-05-22 18:18





AngularJS xử lý cơ chế ràng buộc dữ liệu với sự trợ giúp của ba hàm mạnh mẽ: $ watch (),$ digest ()$ áp dụng (). Hầu hết thời gian AngularJS sẽ gọi phạm vi $. $ Watch () và $ scope. $ Digest (), nhưng trong một số trường hợp, bạn có thể phải gọi các hàm này theo cách thủ công để cập nhật với các giá trị mới.

$ watch () : -

Hàm này được sử dụng để quan sát các thay đổi trong một biến trên phạm vi $.   Nó chấp nhận ba tham số: biểu thức, đối tượng nghe và bình đẳng,   trong đó đối tượng nghe và bình đẳng là các tham số tùy chọn.

$ digest () - -

Hàm này lặp qua tất cả các đồng hồ trong đối tượng $ scope,   và các đối tượng $ scope con của nó
     (nếu có). Khi $ digest () lặp lại   trên đồng hồ, nó sẽ kiểm tra xem giá trị của biểu thức có   đã thay đổi. Nếu giá trị đã thay đổi, AngularJS gọi người nghe bằng   giá trị mới và giá trị cũ. Hàm $ digest () được gọi   bất cứ khi nào AngularJS nghĩ rằng nó là cần thiết. Ví dụ: sau một nút   bấm vào, hoặc sau một cuộc gọi AJAX. Bạn có thể có một số trường hợp mà AngularJS   không gọi hàm $ digest () cho bạn. Trong trường hợp đó bạn phải   gọi nó là chính mình.

$ áp dụng () - -

Góc làm tự động kỳ diệu cập nhật chỉ những thay đổi mô hình được   bên trong bối cảnh AngularJS. Khi bạn thay đổi bất kỳ mô hình nào bên ngoài   bối cảnh Góc (như các sự kiện DOM của trình duyệt, setTimeout, XHR hoặc thứ ba   bên thư viện), sau đó bạn cần thông báo cho Angular về những thay đổi của   gọi $ apply () theo cách thủ công. Khi cuộc gọi hàm $ apply () kết thúc   AngularJS gọi $ digest () trong nội bộ, vì vậy tất cả các ràng buộc dữ liệu là   đã cập nhật.


12
2018-05-16 15:05



điều này hữu ích với tôi - Jayani Sumudini