2014-04-14 21 views
62

Tôi đang cố gắng hiểu rõ hơn về các sắc thái của việc sử dụng dịch vụ $ timeout trong Angular như một phương thức "an toàn $ áp dụng". Về cơ bản trong các kịch bản mà một đoạn mã có thể chạy để đáp ứng với một sự kiện Góc hoặc một sự kiện không có góc như jQuery hoặc một số sự kiện DOM chuẩn.

Như tôi hiểu điều:. Đang

  1. Wrapping trong $ phạm vi $ áp dụng tác phẩm tốt cho kịch bản mà bạn không đã có trong một vòng lặp tiêu hóa (aka jQuery sự kiện.) Nhưng sẽ nâng cao một lỗi nếu một digest là cơ bản dở dang
  2. đang
  3. Wrapping trong một thời gian chờ $() gọi không có tham số trì hoãn hoạt động cho dù đã có trong một chu kỳ tiêu hóa hay không

Nhìn vào mã nguồn góc, nó trông giống như $ timeout thực hiện cuộc gọi tới $ rootScope. $ apply().

  1. Tại sao không có $ timeout() cũng gây ra lỗi nếu chu kỳ thông báo đang được tiến hành?
  2. Cách tốt nhất để sử dụng phạm vi $. $ Apply() khi bạn biết chắc chắn rằng thông báo chưa được tiến hành và $ timeout() khi cần nó an toàn theo cách nào?
  3. Có phải $ timeout() thực sự là "áp dụng an toàn" có thể chấp nhận được hoặc có gotchas không?

Cảm ơn mọi thông tin chi tiết.

Trả lời

53

Looking at Angular source code, it looks like $timeout makes a call to $rootScope.$apply().

  • Why doesn't $timeout() also raise an error if a digest cycle is already in progress?

$timeout sử dụng dịch vụ góc không có giấy tờ $browser. Cụ thể là nó sử dụng $browser.defer() để ngăn không cho thực hiện chức năng của bạn một cách không đồng bộ qua window.setTimeout(fn, delay), sẽ luôn chạy bên ngoài vòng đời của Vòng đời. Chỉ một lần window.setTimeout đã kích hoạt chức năng của bạn $timeout, hãy gọi $rootScope.$apply().

  • Is the best practice to use $scope.$apply() when you know for sure that a digest won't already be in progress and $timeout() when needing it to be safe either way?

Tôi sẽ nói như vậy. Một trường hợp sử dụng khác là đôi khi bạn cần phải truy cập biến $ scope mà bạn biết sẽ chỉ được khởi tạo sau khi thông báo. Ví dụ đơn giản sẽ là nếu bạn muốn thiết lập trạng thái của một form để dơ bẩn bên trong constructor điều khiển của bạn (vì bất kỳ lý do gì). Nếu không có $ timeout, FormController chưa được khởi tạo và xuất bản lên phạm vi $, do đó, gói $scope.yourform.setDirty() bên trong $ timeout đảm bảo rằng FormController đã được khởi tạo. Chắc chắn bạn có thể làm tất cả điều này với một chỉ thị mà không có $ timeout, chỉ cần đưa ra một ví dụ về ca sử dụng khác.

  • Is $timeout() really an acceptable "safe apply", or are there gotchas?

Nên luôn luôn an toàn, nhưng phương pháp tiếp cận của bạn nên luôn hướng tới $ apply() theo ý kiến ​​của tôi. Ứng dụng Angular hiện tại tôi đang làm việc khá lớn và chúng tôi chỉ phải dựa vào $ timeout một lần thay vì $ apply().

+0

trong dự án của tôi, tôi có một kịch bản mà tôi cần phải tăng $ scope. $ digest() để nắm bắt các sự kiện xảy ra bên ngoài khung nhìn của Angular. orm cho safeApply hoặc safeDigest hoặc điều này đã được cố định thông minh bên trong khuôn khổ? – TrueBlue

+1

Tại sao bạn cần phải dựa vào '$ timeout' thay vì' $ apply'? Nếu bạn không thể chia sẻ mã, bạn có thể ít nhất là thảo luận về lý do cơ bản? – trysis

4

Theo như tôi hiểu nó, $timeout là một wrapper quanh setTimeout mà mặc nhiên gọi $scope.$apply, có nghĩa là nó chạy bên ngoài của vòng đời góc, nhưng kickstarts vòng đời góc riêng của mình. Tôi chỉ có thể nghĩ rằng nếu bạn mong đợi kết quả có sẵn $digest, bạn cần tìm cách khác để "áp dụng an toàn" (trong đó, AFAIK, chỉ khả dụng qua $scope.$$phase).

13

Nếu chúng ta sử dụng $ áp dụng rất nhiều trong ứng dụng, chúng tôi có thể nhận được lỗi: $ digest đã được tiến hành. Điều này xảy ra vì một chu kỳ $ digest có thể được chạy cùng một lúc. Chúng tôi có thể giải quyết nó bằng $ timeout hoặc $ evalAsync.

Thời gian chờ $ không tạo ra lỗi như "$ digest đang được tiến hành" vì $ timeout cho Angular biết rằng sau chu kỳ hiện tại, có thời gian chờ chờ và cách này đảm bảo sẽ không có bất kỳ xung đột nào giữa chu kỳ tiêu hóa và do đó sản lượng của $ timeout sẽ thực hiện trên một mới chu kỳ $ tiêu hóa

tôi cố gắng giải thích cho họ tại địa chỉ:... Comparison of apply, timeout,digest and evalAsync

có thể nó sẽ giúp bạn

+0

Bạn chính xác và đầu vào của bạn đã được xem xét. –

+0

Cảm ơn Rahul, bài viết rất thú vị. Những gì tôi cảm thấy nó đã mất tích mặc dù là một đề nghị sử dụng, hoặc sử dụng khi nào. Cảm ơn một lần nữa. –

+1

Cảm ơn Matty về đầu vào. Theo tôi, $ evalAsync là lựa chọn tốt hơn so với tùy chọn có sẵn. –

Các vấn đề liên quan