Sự khác biệt giữa $ evalAsync và $ timeout trong AngularJS là gì?


180

Tôi đã sử dụng AngularJS được một lúc rồi và thấy rằng cần phải sử dụng $ timeout mỗi lần (Có vẻ như thường là để khởi tạo một plugin jQuery).

Gần đây, tôi đã cố gắng để hiểu rõ hơn và sâu hơn về chu trình tiêu hóa và tôi đã tìm thấy hàm $ evalAsync .

Có vẻ như chức năng đó tạo ra kết quả tương tự $timeout, chỉ có điều bạn không trì hoãn. Mỗi lần tôi sử dụng, $timeoutnó có độ trễ bằng 0, vì vậy bây giờ tôi tự hỏi liệu tôi có nên sử dụng $evalAsyncthay thế không.

Có sự khác biệt cơ bản nào giữa hai người không? Những trường hợp bạn sẽ sử dụng một trong những trường hợp khác? Tôi muốn có được cảm giác tốt hơn khi sử dụng cái nào.

Câu trả lời:


263

Gần đây tôi đã trả lời về câu hỏi này tại đây: https://stackoverflow.com/a/17239084/215945 (Câu trả lời đó liên kết đến một số trao đổi github với Misko.)

Để tóm tắt:

  • nếu mã được xếp hàng bằng cách sử dụng $ evalAsync từ một lệnh , nó sẽ chạy sau khi DOM bị thao túng bởi Angular, nhưng trước khi trình duyệt kết xuất lại
  • nếu mã được xếp hàng bằng cách sử dụng $ evalAsync từ bộ điều khiển , nó sẽ chạy trước khi DOM bị thao túng bởi Angular (và trước khi trình duyệt hiển thị) - hiếm khi bạn muốn điều này
  • nếu mã được xếp hàng bằng cách sử dụng $ timeout , nó sẽ chạy sau khi DOM bị thao túng bởi Angular và sau khi trình duyệt kết xuất lại (có thể gây ra nhấp nháy trong một số trường hợp)

15
Cám ơn vì đã giải thích. Một điều tôi không chắc là tôi hiểu. Tại sao nó lại tạo ra sự khác biệt nếu bạn gọi $ evalAsync từ bộ điều khiển hoặc chỉ thị? AsyncQueue không biết liệu nó đã được đăng ký từ bộ điều khiển hay chỉ thị hay chưa, nó chỉ xếp hàng trên phạm vi hiện tại. Nó có phải làm gì khi công cụ chạy trong bộ điều khiển so với bộ điều khiển không? Tôi chỉ muốn hiểu phần đó.
dnc253

@ dnc253, tôi chưa xem mã Angular, vì vậy tôi không biết câu trả lời cho câu hỏi (tốt) của bạn. Hy vọng người khác có thể bình luận.
Mark Rajcok

15
"từ một chỉ thị" có nghĩa là "từ chức năng liên kết của một chỉ thị"? Hoặc điều đó có đúng với hành vi khi được thực thi từ phương thức liên kết hoặc bộ điều khiển của một lệnh không?
SimplGy

5
vâng, nó thực sự không rõ ràng những gì "từ một chỉ thị" và "từ một bộ điều khiển" có nghĩa là ở đây
cái gai

1
@MarkRajcok, bạn có thể vui lòng làm rõ ở đây: nếu mã được xếp hàng bằng cách sử dụng $ evalAsync từ một lệnh, thì nó nên chạy sau khi DOM bị thao túng bởi Angular - nên chạy sau khi DOM bị thao túng bởi lệnh này hay bởi các lệnh khác?
Max Koretskyi

59

Đối với những người xây dựng các ứng dụng phức tạp, hãy lưu ý rằng có một tác động hiệu suất đến sự lựa chọn của bạn. Ngoài ra, tôi muốn hoàn thành câu trả lời Mark với nhiều chi tiết kỹ thuật hơn:

  • $ timeout (gọi lại) sẽ đợi chu trình phân loại hiện tại được thực hiện (tức là cập nhật góc tất cả mô hình và DOM), sau đó nó sẽ thực hiện gọi lại - có khả năng ảnh hưởng đến mô hình góc - sau đó khởi chạy đầy đủ $applytrên phạm vi $ root và chuyển hướng mọi điều.

  • $ evalAsync (gọi lại) , mặt khác, sẽ thêm cuộc gọi lại vào chu trình tiêu hóa hiện tại hoặc tiếp theo. Điều đó có nghĩa là nếu bạn đang ở trong một chu trình phân loại (ví dụ trong một hàm được gọi từ một số lệnh ng-click), điều này sẽ không chờ đợi bất cứ điều gì, mã sẽ được thực thi ngay lập tức. Nếu bạn đang trong một cuộc gọi không đồng bộ, ví dụ a setTimeout, một chu trình phân loại mới ( $apply) sẽ được kích hoạt.

Vì vậy, về mặt hiệu suất, luôn luôn tốt hơn để gọi $evalAsync, trừ khi điều quan trọng đối với bạn là chế độ xem được cập nhật trước khi thực thi mã của bạn, ví dụ nếu bạn cần truy cập vào một số thuộc tính DOm như chiều rộng phần tử và tương tự.

Nếu bạn muốn biết thêm chi tiết về sự khác biệt giữa $ timeout, $ evalAsync, $ digest, $ áp dụng, tôi mời bạn đọc câu trả lời của tôi về câu hỏi khác đó: https://stackoverflow.com/a/23102223/1501926

Cũng hãy chắc chắn đọc tài liệu :

$ EvalAsync không đảm bảo khi nào biểu thức sẽ được thực thi, chỉ có điều:

  • nó sẽ thực thi sau khi chức năng lên lịch đánh giá (tốt nhất là trước khi kết xuất DOM).
  • ít nhất một chu kỳ $ digest sẽ được thực hiện sau khi thực hiện biểu thức.

Lưu ý: nếu chức năng này được gọi bên ngoài chu trình $ digest, chu kỳ $ digest mới sẽ được lên lịch . Tuy nhiên, khuyến khích luôn gọi mã thay đổi mô hình từ trong cuộc gọi áp dụng $. Điều đó bao gồm mã được đánh giá qua $ evalAsync.


Bạn có thể giải thích tại sao $ timeout là cần thiết nếu tôi cần truy cập một số thuộc tính DOM. Giả sử nếu tôi có <table width = "{{x}}"> Chức năng đồng hồ của ng-bind không cập nhật thuộc tính dom trong bộ nhớ, tôi hiểu rằng nó sẽ không có cơ hội để sơn lại chế độ xem cho đến khi thoát khỏi chu trình tiêu hóa.
Sridhar Chidurala

2
@SridharChidurala vì DOM ("HTML") được cập nhật trong chu trình phân loại, bạn phải đợi nó được thực hiện trước khi bạn có thể đọc các thông tin. Tuy nhiên, điều này không được Angular khuyến khích, bạn nên đọc xtrực tiếp từ phạm vi của mình chứ không phải từ DOM, vì vậy bạn không phải chờ đợi điều gì. Ngoài ra, bạn nên sử dụng tốt hơn ng-stylevới css hơn là thuộc tính lỗi thời width. Nếu bạn cần thêm trợ giúp, vui lòng mở một câu hỏi mới trên StackOverflow.
floribon
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.