$ áp dụng đã có lỗi trong tiến trình


133

Dấu vết ngăn xếp:

Error: $apply already in progress
at Error (<anonymous>)
at beginPhase (file:///android_asset/www/built.min.js:7:22740)
at Object.Scope.$apply (file:///android_asset/www/built.min.js:7:25967)
at navigator.geolocation.getCurrentPosition.that (file:///android_asset/www/built.min.js:13:8670)
at Object.geolocation.getCurrentPosition (file:///android_asset/www/plugins/org.apache.cordova.core.geolocation/www/geolocation.js:122:13)
at Object.getCurrentPosition (file:///android_asset/www/built.min.js:13:8589)
at Object.getCurrentPosition (file:///android_asset/www/built.min.js:13:8277)
at Object.getCurrentCity (file:///android_asset/www/built.min.js:13:8941)
at Object.$scope.locateDevice (file:///android_asset/www/built.min.js:13:10480)
at file:///android_asset/www/built.min.js:7:12292:7

đề cập đến mã này http://pastebin.com/B9V6yvFu

    getCurrentPosition: cordovaReady(function (onSuccess, onError, options) {

        navigator.geolocation.getCurrentPosition(function () {
            var that = this,
                args = arguments;

            if (onSuccess) {
                $rootScope.$apply(function () {
                    onSuccess.apply(that, args);
                });
            }
        }, function () {
            var that = this,
                args = arguments;
            if (onError) {
                $rootScope.$apply(function () {
                    onError.apply(that, args);
                });
            }
        }, {
            enableHighAccuracy: true,
            timeout: 20000,
            maximumAge: 18000000
        });
    })

Điều kỳ lạ, trên LG4X của tôi, nó hoạt động tốt, tuy nhiên trên samsung s2 của tôi, nó đã ném lỗi ở trên. Bất cứ ý tưởng whats sai?


1
Bạn đã thử stackoverflow.com/a/12859093/1266600 chưa? Có thể là do các thiết bị khác nhau -> tốc độ xử lý khác nhau -> thời gian khác nhau, có thể gây ra xung đột ở một số nơi nhưng không phải ở các nơi khác.
sushain97

20
sử dụng$timeout()
Onur Yıldırım

7
+1 cho nhận xét $ timeout (). Xem: stackoverflow.com/questions/12729122/ khăn
Trevor

Câu trả lời:


106

Bạn đang gặp lỗi này vì bạn đang gọi $apply bên trong một chu trình tiêu hóa hiện có.

Câu hỏi lớn là: tại sao bạn gọi $apply? Bạn không bao giờ cần phải gọi $applytrừ khi bạn đang can thiệp từ một sự kiện không phải là Angular. Sự tồn tại của$apply thường có nghĩa là tôi đang làm điều gì đó sai (trừ khi, một lần nữa, áp dụng $ xảy ra từ một sự kiện không phải là Angular).

Nếu $applythực sự phù hợp ở đây, hãy xem xét sử dụng phương pháp "áp dụng an toàn":

https://coderwall.com/p/ngisma


41
Cốt lõi của ứng dụng an toàn được liên kết là một mô hình chống (theo các tài liệu) github.com/angular/angular.js/wiki/Anti-Potypes . Nếu bạn muốn một cách thực hiện trong tương lai (giai đoạn $$ sẽ biến mất!), Hãy bọc mã của bạn trong thời gian chờ $ () mà không đặt thời gian. Nó sẽ áp dụng một cách an toàn sau khi chu trình tiêu hóa hiện tại đã hoàn thành.
betaorbust

@betaorbust Đồng ý. Áp dụng an toàn là xấu. Ngoài ra, gọi áp dụng quá nhiều lần có thể gây ra vấn đề hoàn hảo. Tốt nhất là cấu trúc mã để tránh vấn đề cùng nhau.
Brian Genisio

tôi không gọi điện áp dụng
mạch


41

Bạn có thể sử dụng tuyên bố này:

if ($scope.$root.$$phase != '$apply' && $scope.$root.$$phase != '$digest') {
    $scope.$apply();
}

1
Không nên sử dụng các biến bắt đầu bằng $$ vì chúng là riêng tư. Trong trường hợp này, giai đoạn $$
Ara Yeressian 14/07/2015

9
Câu trả lời này hữu ích hơn nhiều so với câu hỏi trên. Tôi cần một giải pháp, không được cảnh báo cho những thứ có thể nằm ngoài tầm kiểm soát của tôi. Chúng tôi có một hỗn hợp của mã góc và di sản, và họ phải tương tác bằng cách nào đó. Quá tốn kém khi chỉ viết lại tất cả các mã kế thừa ...
Jordan Lapp

24

Nếu phạm vi phải được áp dụng trong một số trường hợp, thì bạn có thể đặt thời gian chờ để $ áp dụng được hoãn lại cho đến khi đánh dấu tiếp theo

setTimeout(function(){ scope.$apply(); });

hoặc bọc mã của bạn trong $ timeout (function () {..}); bởi vì nó sẽ tự động $ áp dụng phạm vi khi kết thúc thực thi. Nếu bạn cần chức năng của mình hoạt động đồng bộ, tôi sẽ thực hiện trước.


Tôi thấy tôi cần bao gồm hành động trong setTimeout(function() { $apply(function() {... do stuff ...} ) })mỗi @Tamil Vendhan bên dưới.
nguyên mẫu

6
Không sử dụng setTimeout, điều đó chỉ tạo ra nhu cầu áp dụng $ khác. Sử dụng khung, nó có một dịch vụ $ timeout làm tất cả những điều đó cho bạn.
Spencer

10

Trong trường hợp của tôi, tôi sử dụng $applyvới giao diện người dùng lịch góc để liên kết một số sự kiện:

$scope.eventClick = function(event){           
    $scope.$apply( function() {
        $location.path('/event/' + event.id);
    });
};

Sau khi đọc tài liệu của vấn đề: https://docs.angularjs.org/error/ $ rootScope / inprog

Phần API không nhất quán (Sync / Async) rất thú vị:

Ví dụ, hãy tưởng tượng một thư viện bên thứ 3 có phương thức sẽ truy xuất dữ liệu cho chúng tôi. Vì nó có thể thực hiện cuộc gọi không đồng bộ đến máy chủ, nên nó chấp nhận chức năng gọi lại, sẽ được gọi khi dữ liệu đến.

Vì, hàm tạo MyControll luôn được khởi tạo từ trong lệnh gọi $ áp dụng, trình xử lý của chúng tôi đang cố gắng nhập một khối áp dụng $ mới từ bên trong một.

Tôi thay đổi mã thành:

$scope.eventClick = function(event){           
    $timeout(function() {
        $location.path('/event/' + event.id);
    }, 0);
};

Hoạt động như một lá bùa!

Ở đây, chúng tôi đã sử dụng $ timeout để lên lịch thay đổi phạm vi trong ngăn xếp cuộc gọi trong tương lai. Bằng cách cung cấp khoảng thời gian chờ là 0ms, điều này sẽ xảy ra càng sớm càng tốt và $ timeout sẽ đảm bảo rằng mã sẽ được gọi trong một khối áp dụng $ duy nhất.


1
Giải pháp 0 thời gian chờ 0 của bạn là Tuyệt vời.
Ahsan

9

Trong góc 1.3, tôi nghĩ, họ đã thêm một chức năng mới - $scope.$applyAsync(). Các cuộc gọi chức năng này áp dụng sau này - ít nhất họ nói khoảng 10 ms sau. Nó không hoàn hảo, nhưng ít nhất nó cũng loại bỏ được lỗi khó chịu.

https://docs.angularjs.org/api/ng/type/ $ rootScope.Scope # $ áp dụngAsync


3

Tại bất kỳ thời điểm nào, có thể chỉ có một $digesthoặc $applyhoạt động trong tiến trình. Điều này là để ngăn chặn rất khó để phát hiện lỗi xâm nhập vào ứng dụng của bạn. Theo dõi ngăn xếp của lỗi này cho phép bạn theo dõi nguồn gốc của cuộc gọi $applyhoặc $digestcuộc gọi hiện đang thực hiện , điều này gây ra lỗi.

Thông tin thêm: https://docs.angularjs.org/error/$rootScope/inprog?p0=$apply


2

Chỉ cần giải quyết vấn đề này. Tài liệu của nó ở đây .

Tôi đã gọi $rootScope.$applyhai lần trong cùng một dòng. Tất cả tôi đã làm là bọc nội dung của chức năng dịch vụ với a setTimeout(func, 1).


1

Tôi biết đó là câu hỏi cũ nhưng nếu bạn thực sự cần sử dụng $ scope. $ ApplicationAsync ();


0

Tôi gọi $ scope. $ Áp dụng như thế này để bỏ qua cuộc gọi nhiều lần trong một lần.

      var callApplyTimeout = null;
      function callApply(callback) {
          if (!callback) callback = function () { };
          if (callApplyTimeout) $timeout.cancel(callApplyTimeout);

          callApplyTimeout = $timeout(function () {
              callback();
              $scope.$apply();
              var d = new Date();
              var m = d.getMilliseconds();
              console.log('$scope.$apply(); call ' + d.toString() + ' ' + m);
          }, 300);
      }

chỉ cần gọi

callApply();
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.