$ застосувати вже запущену помилку


133

Слід стека:

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

посилається на цей код 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
        });
    })

Дивна річ, на моєму LG4X він працює чудово, однак на моєму samsung s2 він видає вказану вище помилку. Будь-які ідеї, що не так?


1
Ви спробували stackoverflow.com/a/12859093/1266600 ? Це може бути через те, що різні пристрої -> різна швидкість обробки -> різні терміни, що може спричинити конфлікти в деяких місцях, але не в інших.
sushain97

20
використання$timeout()
Onur Yıldırım

7
+1 до коментаря $ timeout (). Дивіться: stackoverflow.com/questions/12729122/…
Тревор

Відповіді:


106

Ви отримуєте цю помилку, оскільки ви телефонуєте $applyвсередині існуючого циклу травлення.

Велике питання: чому ти дзвониш $apply? Вам ніколи не потрібно дзвонити, $applyякщо ви не зв’яжетеся з невугловою подією. Існування $applyзазвичай означає, що я роблю щось не так (якщо, знову ж таки, застосунок $ не трапляється з події, що не стосується кута).

Якщо тут $applyдійсно доречно, спробуйте скористатися підходом "безпечного застосування":

https://coderwall.com/p/ngisma


41
Основою пов’язаного безпечного застосунку є анти-візерунок (згідно з документами) github.com/angular/angular.js/wiki/Anti-Patterns . Якщо ви хочете, щоб це підтримувалось у майбутньому ($$ фаза йде!), Загорніть свій код у $ timeout () без встановленого часу. Це надійно застосовуватиметься після завершення поточного циклу дайджесту.
betaorbust

@betaorbust Погодився. Безпечне застосування - це погано. Крім того, дзвінки, що застосовуються занадто багато разів, можуть спричинити проблеми з перф. Найкраще структурувати код, щоб уникнути проблеми разом.
Брайан Генісіо

я не закликаю застосовувати
схема


41

Ви можете використовувати це твердження:

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

1
Не рекомендується використовувати змінні, які починаються з $$, оскільки вони приватні. У цьому випадку фаза $$
Ара Єресіан

9
Ця відповідь набагато корисніша, ніж наведена вище. Мені потрібно рішення, а не наказувати мені щось, що може бути поза моїм контролем. У нас є суміш кутових і застарілих кодів, і вони повинні якось взаємодіяти. Це занадто дорого, щоб просто переписати всі застарілі коди ...
Jordan Lapp,

24

Якщо область застосування повинна застосовуватися в деяких випадках, то ви можете встановити тайм-аут, щоб відмітка $ застосувалась до наступного галочки

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

або загорніть код у $ timeout (function () {..}); тому що він автоматично застосує область в кінці виконання. Якщо вам потрібна ваша функція, щоб вести себе синхронно, я б зробив перше.


Я виявив, що мені потрібно включити дію в setTimeout(function() { $apply(function() {... do stuff ...} ) })per @Tamil Vendhan нижче.
прототип

6
Не використовуйте setTimeout, що просто створює потребу в додатку $ application. Скористайтеся фреймворком, у ньому є сервіс $ timeout, який робить все, що для вас.
Спенсер

10

У моєму випадку я використовую $applyз кутовим інтерфейсом календаря, щоб пов’язати якусь подію:

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

Прочитавши документ проблеми: https://docs.angularjs.org/error/ $ rootScope / inprog

Частина непослідовний API (Sync / Async) дуже цікава:

Наприклад, уявіть сторонню бібліотеку, яка має метод, який дозволяє отримати дані для нас. Оскільки він може здійснювати асинхронний дзвінок на сервер, він приймає функцію зворотного дзвінка, яка буде викликана, коли дані надійдуть.

Оскільки конструктор MyController завжди інстанціюється в межах виклику $ apply, наш обробник намагається ввести новий блок застосунку $ зсередини одного.

Я змінюю код на:

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

Працює як шарм!

Тут ми використали $ timeout, щоб запланувати зміни в області застосування в майбутньому стеку викликів. Забезпечивши період очікування 0ms, це відбудеться якомога швидше, і $ timeout забезпечить виклик коду в одному блоці $ apply.


1
Рішення з затримкою 0 $ затримки - дивовижне.
Ahsan

9

У кутовому 1.3, я думаю, вони додали нову функцію - $scope.$applyAsync(). Виклики цієї функції застосовуються пізніше - вони говорять про 10 мс принаймні пізніше. Це не досконало, але це принаймні усуває дратівливу помилку.

https://docs.angularjs.org/api/ng/type/ $ rootScope.Scope # $ applyAsync


3

У будь-який момент часу може бути лише одна $digestабо виконувана $applyоперація. Це запобігає надходженню помилок у вашій програмі. Слід стека цієї помилки дозволяє простежити походження поточного виконання $applyабо $digestвиклику, що спричинило помилку.

Більше інформації: https://docs.angularjs.org/error/$rootScope/inprog?p0=$apply


2

Щойно вирішено це питання. Її тут задокументовано .

Я дзвонив $rootScope.$applyдвічі одним і тим же потоком. Все, що я зробив, це обгорнув вміст службової функції з a setTimeout(func, 1).


1

Я знаю, що це старе питання, але якщо вам дійсно потрібно використовувати $ range. $ ApplyAsync ();


0

Я закликаю $ range. $ Застосовується так, щоб ігнорувати виклик, кілька разів за один раз.

      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);
      }

просто зателефонуйте

callApply();
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.