Angular.js: 在 iOS 9 w/UIWebView 上位置变化的无限摘要(不在 Safari/WKWebView 中)

创建于 2015-06-30  ·  154评论  ·  资料来源: angular/angular.js

以下简单的 HTML 演示了该问题:

<!DOCTYPE html>
<html>
    <head>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.16/angular.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.16/angular-route.js"></script>
        <script>
            angular.module('fail', ['ngRoute'])
            .config(function($routeProvider) {
                $routeProvider
                .when('/a', {
                    template: '<a ng-href="#/b">a</a>'
                })
                .when('/b', {
                    template: '<a ng-href="#/a">b</a>'
                })
                .otherwise({
                    redirectTo: '/a'
                });
            });
        </script>
    </head>
    <body ng-app="fail">
        <div ng-view></div>
    </body>
</html>

这在大多数设备上按预期运行,但在 iOS 9 上会引发无限摘要异常。
我可以在装有 iOS 9 beta 2 的 iPad Air 2 和 iPad 4 代上重现。
我意识到这可能是 iOS 中的一个问题,但它可能仍然值得调查。

iOS $location bug

最有用的评论

在这一点上更进一步。 我在 Angular 中对位置进行了更改。
在“更新浏览器”部分,我将 $rootScope.$evalAsync 更改为 $rootScope.$applyAsync。

这两种方法看起来完全一样。 在您查看实际的 $digest 执行之前,差异不会变得明显。 当 AngularJS 执行摘要时,它会遍历 Scope 树并执行 $watch() 绑定,直到不再产生脏数据。 在这个生命周期中,$applyAsync() 队列和 $evalAsync() 队列都会被刷新; 但是,这发生在两个非常不同的地方。

$applyAsync() 队列只会在 AngularJS 开始检查脏数据之前在 $digest 的顶部刷新。 因此,$applyAsync() 队列将在 $digest 期间最多被刷新一次,并且只有在 $digest 开始之前队列已经被填充时才会被刷新。

另一方面,$evalAsync() 队列在实现 $digest 内部“脏检查”的 while 循环的顶部刷新。 这意味着在摘要期间添加到 $evalAsync() 队列的任何表达式都将在同一摘要中稍后执行。

为了使这种差异更加具体,这意味着 $evalAsync() 从 $watch() 绑定中添加的异步表达式将在相同的摘要中执行。 $applyAsync() 从 $watch() 绑定中添加的异步表达式将在稍后的时间点(~10ms)执行。

希望这已经对你们中的一些人有所帮助:-)。


// update browser
    $rootScope.$watch(function $locationWatch() {
      var oldUrl = trimEmptyHash($browser.url());
      var newUrl = trimEmptyHash($location.absUrl());
      var oldState = $browser.state();
      var currentReplace = $location.$$replace;
      var urlOrStateChanged = oldUrl !== newUrl ||
        ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);

      if (initializing || urlOrStateChanged) {
        initializing = false;

        $rootScope.$applyAsync(function() {
          var newUrl = $location.absUrl();
          var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
              $location.$$state, oldState).defaultPrevented;

          // if the location was changed by a `$locationChangeStart` handler then stop
          // processing this location change
          if ($location.absUrl() !== newUrl) return;

          if (defaultPrevented) {
            $location.$$parse(oldUrl);
            $location.$$state = oldState;
          } else {
            if (urlOrStateChanged) {
              setBrowserUrlWithFallback(newUrl, currentReplace,
                                        oldState === $location.$$state ? null : $location.$$state);
            }
            afterLocationChange(oldUrl, oldState);
          }
        });
      }

      $location.$$replace = false;

      // we don't need to return anything because $evalAsync will make the digest loop dirty when
      // there is a change
    });

所有154条评论

我遇到了类似的问题,它发生在 ios 9 上,但在其他设备上运行正常。

我用 santaslow 在 1.4.1 / ios 9 上提供的相同代码重现了这个问题:

<!DOCTYPE html>
<html>
<head>
    <script src="../static/js/angular/angular.1.4.1.js"></script>
    <script src="../static/js/angular-route/angular-route.1.4.1.js"></script>
    <script>
        angular.module('fail', ['ngRoute'])
                .config(function ($routeProvider) {
                    $routeProvider
                            .when('/a', {
                                template: '<a ng-href="#/b">a</a>'
                            })
                            .when('/b', {
                                template: '<a ng-href="#/a">b</a>'
                            })
                            .otherwise({
                                redirectTo: '/a'
                            });
                }).factory('$exceptionHandler', ['$log', function($log) {
                    return function(exception, cause) {
                        var message = 'angularjs exception: '+exception.message+': caused by "' + cause+ '\njs stack:\n'+exception.stack;
                        $log.error(message);
                    };
                }]);
    </script>
</head>
<body ng-app="fail">
<div ng-view></div>
</body>
</html>

上面的代码在桌面浏览器、android和ios 8 webview上正常运行,但在ios 9上点击链接时会抛出异常

2015-07-02 11:00:09 ... angularjs exception: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: []
http://errors.angularjs.org/1.4.1/$rootScope/infdig?p0=10&p1=%5B%5D: caused by "undefined
js stack:
file:///.../static/js/angular/angular.js:68:32
$digest<strong i="10">@file</strong>:///.../static/js/angular/angular.js:15705:35
$apply<strong i="11">@file</strong>:///.../static/js/angular/angular.js:15935:31
file:///.../static/js/angular/angular.js:12070:30
eventHandler<strong i="12">@file</strong>:///.../static/js/angular/angular.js:3264:25

我无法再在 iOS 9 Beta 3 中重现。

我在 ios9 public beta (13A4293g) 上收到同样的错误

我在 ios 9 beta 3 (13A4293g) 上验证了上面的代码,不再例外。 但是使用 ng-view 的应用程序仍然在 ios 9 beta 3 上抛出 infdig 异常。

我在 ios9 public beta (13A4293g) 上收到同样的错误

错误:[$ rootScope:infdig ] 10 $digest() 迭代达到。 中止!
在最后 5 次迭代中触发的观察者:[]
http://errors.angularjs.org/1.3.13/ $rootScope/infdig?p0=10&p1=%5B%5D
file:///Users/mac5/Library/Developer/CoreSimulator/Devices/749DE7E3-D93F-47F9-A1FC-E3D54A1CCEEE/data/Containers/Bundle/Application/9B5EE368-F2A0-4C99-807B-EA17E3D54A1CCEEE/data/Containers/Bundle/Application/9B5EE368-F2A0-4C99-807B-EA17E3D54A1CCEEE /lib/ionic/js/ionic.bundle.js:8762:32
$digest@file :///Users/mac5/Library/Developer/CoreSimulator/Devices/749DE7E3-D93F-47F9-A1FC-E3D54A1CCEEE/data/Containers/Bundle/Application/9B5EE368-F2A0-4C99-8072B-4E1A1HOP app/www/lib/ionic/js/ionic.bundle.js:22980:35
$apply@file :///Users/mac5/Library/Developer/CoreSimulator/Devices/749DE7E3-D93F-47F9-A1FC-E3D54A1CCEEE/data/Containers/Bundle/Application/9B5EE368-F2A0-4C99-807B-47E3Hop app/www/lib/ionic/js/ionic.bundle.js:23205:31
file:///Users/mac5/Library/Developer/CoreSimulator/Devices/749DE7E3-D93F-47F9-A1FC-E3D54A1CCEEE/data/Containers/Bundle/Application/9B5EE368-F2A0-4C99-807B-EA17E3D54A1CCEEE/data/Containers/Bundle/Application/9B5EE368-F2A0-4C99-807B-EA17E3D54A1CCEEE /lib/ionic/js/ionic.bundle.js:54879:24
eventHandler@file :///Users/mac5/Library/Developer/CoreSimulator/Devices/749DE7E3-D93F-47F9-A1FC-E3D54A1CCEEE/data/Containers/Bundle/Application/9B5EE368-F2A0-4C99-807B-4BA9E75B /www/lib/ionic/js/ionic.bundle.js:11713:25
dispatchEvent@[本机代码]
triggerMouseEvent@file :
tapClick@file :
tapTouchEnd@file :

我们也在使用我们自己的 Angular 应用程序的 iOS 9 的公共 Beta 3 上收到此错误。 它不会发生在 iOS 8 中。

作为一种解决方法,我编写了一个简单的指令来替换 ng-view 和 angular-route.js。 该解决方案在我们自己的应用程序中运行良好,所有 infdig 异常在 ios 9 beta/beta 3 上都消失了。以下是简化代码,仅针对我们自己的应用程序,不考虑一般用例。 我不推荐其他人使用这个:

(function (window) {
    'use strict';

    var myApp = angular.module("myApp");
    var $route = {};

    // replace $routeProvider.when with the function below:
    window.routeWhen = function(path, route) {
        $route[path] = route;
    };

    myApp.directive("myView", ['$compile', '$controller', '$http', '$rootScope', function ($compile, $controller, $http, $rootScope) {

        return {
            priority: -400,
            link: function (scope, element) {
                var parentScope = scope;
                scope = null;

                window.updateView = function (path) {
                    location.hash = '#'+url;
                    if (scope) scope.$destroy();
                    scope = parentScope.$new();

                    var route = $route[path];

                    var linkView = function(html) {
                        element.html(html);
                        var link = $compile(element.contents());
                        var controller = $controller(route.controller, {$scope: scope});
                        element.data('$ngControllerController', controller);
                        element.children().data('$ngControllerController', controller);
                        link(scope);
                        scope.$emit('$viewContentLoaded');
                        if (!$rootScope.$$phase && !scope.$$phase) scope.$apply();
                    };
                    if (route.templateCache) linkView(route.templateCache)
                    else if (route.template) {
                        route.templateCache = document.getElementById(route.template).innerHTML;
                        linkView(route.templateCache)
                    }
                    else $http.get(route.templateUrl;).success(function(html) {
                        route.templateCache = html;
                        linkView(html);
                    });
                };
                //updateView(initialPath);
                // call updateView(path) to set location at other places of the app
            }
        };
    }]);

})(window)

刚刚安装了 iOS 9 Beta 4 并且仍然有同样的问题。 还有谁?

我在 iOS 9 Beta 3 中看到它,我仍然在 iOS 9 Beta 4 中看到它。

+1

是的,即使使用 angular ui 路由器,我们也看到了同样的问题。 在此期间,是否有人对此问题有有效的解决方法?

在最新的 iOS9 上的 uiWebView 中看到同样的问题。

有没有人对此问题有任何更新?

这仍然是一个问题。 重新开放

好像是ios的问题。 这是在某个地方的 webkit 上跟踪的吗?

+1

+1

同样在这里。 如果在 iPad Safari 上作为网络运行,我们的 Cordova 应用程序运行良好,但如果它作为 Cordova 应用程序 (UIWebView) 运行,则会发生无限摘要。

@borrull完全相同的问题! 已经用 WKWebView 进行了试验,然后问题就不存在了。 但是我们不能使用 WKWebView,因为我们需要本地文件服务(并且我们不想在我们的应用程序中运行本地服务器)和 cookie。 所以它必须在 iOS 9 上将 UIWebView 与 Cordova/Mobile Safari 结合起来做一些事情。我目前正在 Angular 中调试 $locationWatch,因为我看到我们的应用程序想要多次转换到不同的位置,然后(10 次之后) ) 抛出摘要错误。

在 iOS9 beta4 上也有同样的问题
角度无限 $digest 循环 ;(

+1,仅在 UIWebView 中,不在 WKWebView 中,但我们只能在我们的cordova 应用程序中使用 UIWebView。

+1

如果这是 iOS 特定问题,请在 webkit 问题跟踪器上打开问题并提供演示! +1 在这里不太可能改变任何东西,因为它真的听起来像一个浏览器错误。

有人向 Apple 报告了此错误以进行调查吗?

我向苹果报告了这个错误。 但也许你们都应该做同样的事情来引起他们对错误的关注。

你能给我们一个链接以便我们可以 +1 吗?

它通过错误报告器在我们的个人苹果帐户中..所以没有公共链接;(

你能把它发布到 openradar 并分享 rdar id 以便我们可以欺骗它!

在 iOS9 测试版 5 上相同:
适用于移动 Safari
适用于我们无法使用的 WKWebview,因为它无法提供本地文件并且不支持 NSProtocol
不适用于 UIWebView

在 IOS 9 Beta 5 上也一样

我也向 Apple 提交了一个错误。 Open Radar 链接是: https : @santaslow在 OP 中提供 JS)

我已经创建了相同 Xcode 项目的一个版本(来自@borrull),但使用 ui-router 而不是 ng-route。 完全一样的问题。 有兴趣的朋友可以在这里找到项目: http :

我们也看到了这样的问题。 我能够将问题归结为 location.* 属性在 angular 混合时不会立即更新。 如果您尝试为 location.hash 分配一个值(就像在定位服务后面所做的那样),然后立即读回它,该值没有改变。 由于 jqlite 处理程序附加到 popstate 和 hashchanged 事件,似乎会发生一些副作用。

当我在电脑上时,我会尝试上传一个样本。

+1

@CleverCoder样本有任何更新吗?

我必须在早上完成复制案例,因为我整个周末都在使用代码。 谢谢你的轻推! 随着 iOS 9 倒计时,我们有兴趣看到这个问题的解决。 我会尽快上传一些东西。

+1

我已经重现了我认为的根本原因,即设置位置哈希或 href 属性不会立即“应用”。
这是 XCode 项目的链接:
https://www.dropbox.com/s/2jkwv2thhm86nly/iOS%209%20Location%20Bug.zip?dl=0
如果您无法访问该文件,请告诉我。

观察 location.hash 中的结果值,并附加 Safari 进行调试。 由于基于“popstate”和“hashchange”事件的某些事件管道,似乎有些东西推迟了更改。

我希望这是有帮助的。

  • 肖恩

我们正在使用 window.location.href 而不是 state.go 并且它现在似乎正在工作。 少越野车。

location.hash 的值将在 runloop 旋转后正确。 Angular 可以通过延迟 setTimeout(..., 0) 中的 location.hash 来轻松解决这个问题。 我认为这将是对 angular.js/src/ng/location.js 的约 2 处更改。

@hober像这样尝试使用 angular 超时:

// update $location when $browser url changes
    $browser.onUrlChange(function(newUrl, newState) {
      $rootScope.$evalAsync(function() {
        var oldUrl = $location.absUrl();
        var oldState = $location.$$state;
        var defaultPrevented;

        $location.$$parse(newUrl);
        $location.$$state = newState;

        defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
            newState, oldState).defaultPrevented;

        // if the location was changed by a `$locationChangeStart` handler then stop
        // processing this location change
        if ($location.absUrl() !== newUrl) return;

        if (defaultPrevented) {
          $location.$$parse(oldUrl);
          $location.$$state = oldState;
          setTimeout(function(){ setBrowserUrlWithFallback(oldUrl, false, oldState) }, 0);
        } else {
          initializing = false;
          afterLocationChange(oldUrl, oldState);
        }
      });
      if (!$rootScope.$$phase) $rootScope.$digest();
    });

// update browser
    $rootScope.$watch(function $locationWatch() {
      var oldUrl = trimEmptyHash($browser.url());
      var newUrl = trimEmptyHash($location.absUrl());
      var oldState = $browser.state();
      var currentReplace = $location.$$replace;
      var urlOrStateChanged = oldUrl !== newUrl ||
        ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);

      if (initializing || urlOrStateChanged) {
        initializing = false;

        $rootScope.$evalAsync(function() {
          var newUrl = $location.absUrl();
          var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
              $location.$$state, oldState).defaultPrevented;

          // if the location was changed by a `$locationChangeStart` handler then stop
          // processing this location change
          if ($location.absUrl() !== newUrl) return;

          if (defaultPrevented) {
            $location.$$parse(oldUrl);
            $location.$$state = oldState;
          } else {
            if (urlOrStateChanged) {
              setTimeout(function(){ setBrowserUrlWithFallback(newUrl, currentReplace,
                  oldState === $location.$$state ? null : $location.$$state) }, 0);
            }
            afterLocationChange(oldUrl, oldState);
          }
        });
      }

      $location.$$replace = false;

      // we don't need to return anything because $evalAsync will make the digest loop dirty when
      // there is a change
    });

所以我在 setBrowserUrlWithFallback 方法周围添加了一个 setTimout ,但它没有解决问题。

这是一个不依赖于 Angular 的简化测试用例,它演示了解决方法。 我不清楚如何在 Angular 中实际实施解决方法。 https://gist.github.com/hober/a29b6c28ac1744c800dd

在这一点上更进一步。 我在 Angular 中对位置进行了更改。
在“更新浏览器”部分,我将 $rootScope.$evalAsync 更改为 $rootScope.$applyAsync。

这两种方法看起来完全一样。 在您查看实际的 $digest 执行之前,差异不会变得明显。 当 AngularJS 执行摘要时,它会遍历 Scope 树并执行 $watch() 绑定,直到不再产生脏数据。 在这个生命周期中,$applyAsync() 队列和 $evalAsync() 队列都会被刷新; 但是,这发生在两个非常不同的地方。

$applyAsync() 队列只会在 AngularJS 开始检查脏数据之前在 $digest 的顶部刷新。 因此,$applyAsync() 队列将在 $digest 期间最多被刷新一次,并且只有在 $digest 开始之前队列已经被填充时才会被刷新。

另一方面,$evalAsync() 队列在实现 $digest 内部“脏检查”的 while 循环的顶部刷新。 这意味着在摘要期间添加到 $evalAsync() 队列的任何表达式都将在同一摘要中稍后执行。

为了使这种差异更加具体,这意味着 $evalAsync() 从 $watch() 绑定中添加的异步表达式将在相同的摘要中执行。 $applyAsync() 从 $watch() 绑定中添加的异步表达式将在稍后的时间点(~10ms)执行。

希望这已经对你们中的一些人有所帮助:-)。


// update browser
    $rootScope.$watch(function $locationWatch() {
      var oldUrl = trimEmptyHash($browser.url());
      var newUrl = trimEmptyHash($location.absUrl());
      var oldState = $browser.state();
      var currentReplace = $location.$$replace;
      var urlOrStateChanged = oldUrl !== newUrl ||
        ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);

      if (initializing || urlOrStateChanged) {
        initializing = false;

        $rootScope.$applyAsync(function() {
          var newUrl = $location.absUrl();
          var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
              $location.$$state, oldState).defaultPrevented;

          // if the location was changed by a `$locationChangeStart` handler then stop
          // processing this location change
          if ($location.absUrl() !== newUrl) return;

          if (defaultPrevented) {
            $location.$$parse(oldUrl);
            $location.$$state = oldState;
          } else {
            if (urlOrStateChanged) {
              setBrowserUrlWithFallback(newUrl, currentReplace,
                                        oldState === $location.$$state ? null : $location.$$state);
            }
            afterLocationChange(oldUrl, oldState);
          }
        });
      }

      $location.$$replace = false;

      // we don't need to return anything because $evalAsync will make the digest loop dirty when
      // there is a change
    });

这是另一种方法。 我对 Angular 代码库不太熟悉,但逻辑似乎很合理。 浏览器 url(...) 函数当前依赖于 location.href 立即返回正确的 URL。 因为这个方法是在同一个 run loop 中调用的,所以在 $digest 稳定周期内,它会继续获取旧的 URL。 此补丁利用“pendingHref”来跟踪分配,如果已设置,则返回该值。 一旦该值与 location.href 对齐,则清除挂起的值。 在一组 url 期间,定时器设置为 0ms 以捕获未调用 url() get 的情况。 这并不完美,但逻辑似乎有效。 这主要是为了考虑一种不会造成性能延迟的替代方法。 这是基于 Angular 标签 v1.4.3。

diff --git a/src/ng/browser.js b/src/ng/browser.js
index 928de95..3b9957e 100644
--- a/src/ng/browser.js
+++ b/src/ng/browser.js
@@ -87,7 +87,9 @@ function Browser(window, document, $log, $sniffer) {
   var cachedState, lastHistoryState,
       lastBrowserUrl = location.href,
       baseElement = document.find('base'),
-      reloadLocation = null;
+      reloadLocation = null,
+      pendingHref = null,
+      pendingHrefTimer = null;

   cacheState();
   lastHistoryState = cachedState;
@@ -124,6 +126,18 @@ function Browser(window, document, $log, $sniffer) {
     if (location !== window.location) location = window.location;
     if (history !== window.history) history = window.history;

+    // Schedule cleaning up pendingHref on the next run loop for setting URL. This is to handle
+    // the case where the browser doesn't update the location.* properties immediately
+    if (!pendingHrefTimer && pendingHref && url) {
+      pendingHrefTimer = setTimeout(function () {
+        if (location.href == pendingHref) {
+          console.log('Actual href updated... setting pendingHref to null from setTimeout');
+          pendingHref = null;
+        }
+        pendingHrefTimer = null;
+      }, 0);
+    }
+
     // setter
     if (url) {
       var sameState = lastHistoryState === state;
@@ -147,6 +161,7 @@ function Browser(window, document, $log, $sniffer) {
         // Do the assignment again so that those two variables are referentially identical.
         lastHistoryState = cachedState;
       } else {
+        pendingHref = url;
         if (!sameBase || reloadLocation) {
           reloadLocation = url;
         }
@@ -161,10 +176,22 @@ function Browser(window, document, $log, $sniffer) {
       return self;
     // getter
     } else {
+      var href = location.href.replace(/%27/g, "'");
+      if (pendingHref) {
+        //console.log('.. using pendingHref for url() return value');
+        href = pendingHref;
+      }
+
+      if (location.href == pendingHref) {
+        console.log('Actual href updated... setting pendingHref to null in getter');
+        pendingHref = null;
+      }
+
+      //var href = location.href.replace(/%27/g,"'");
       // - reloadLocation is needed as browsers don't allow to read out
       //   the new location.href if a reload happened.
       // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
-      return reloadLocation || location.href.replace(/%27/g,"'");
+      return reloadLocation || href;
     }
   };

感谢@CleverCoder的解决方案! 似乎很有魅力! :+1:

@聪明的编码器
如果您向 angular 团队发出拉取请求,那就太好了。

@viattik如果 angular 团队会在 iOS9 上采用 UIWebView 的解决方法,我会感到惊讶,因为该错误出在 UIWebView (Apple) 本身中。 但是你可以随时尝试...

@raftheunis87
在不同的浏览器中有很多错误,并且有很多针对 angular 代码中的错误的解决方法。
尽管它们没有正式支持 UIWebView,但在 Apple 修复该错误之前,许多混合应用程序将被破坏,并且在最新的 iOS 中的混​​合应用程序中不可能使用 angular。 我会说这是一个非常大的问题。
所以我想试一试。

@viatik我完全同意。 顺便说一句:Apple 告诉我们,他们不太可能修复 UIWebView 错误。 确实如此:试一试;-)

伙计们,如果您可以将此作为 webkit 错误发布,最好使用重现案例,我将跟进我们在 WebKit 方面的一些联系人。 https://bugs.webkit.org/

@naomiblack
不确定这是否是 webkit 错误。 因为它只发生在 iOS9 上的 UIWebView 中。 iOS9 上的 Safari 工作正常。

@raftheunis87感谢您的代码建议,完美运行

@raftheunis87 @CleverCoder是一种使用 ionic-angular 的方法吗? 你可以说得更详细点吗?

@abrahamrkj我对离子没有任何经验。 但是当使用 ionic 时,他们的定制是否有角度? 否则,我会说相同的修复程序适用于 ionic-angular ......

@raftheunis87 https://github.com/driftyco/ionic/tree/master/js这是他们使用的角度。

@CleverCoder +1 用于拉取请求。 我同意@viattik 的观点,这是一个重要问题,因为它会破坏许多混合应用程序。

拉取请求可能在不久的将来,尽管我犹豫,因为我不像其他人那样接近 Angular 代码库。 我将很快重新审视该解决方案并尝试使其防弹。 window.location 对象上的属性不会“立即”更改,这似乎很奇怪。 在我所做的测试中,我确实注意到只要 'popstate' 和 'hashchange' 事件钩子没有到位,更改确实会保持不变,这让我认为延迟更改的原因实际上可能是做一些事情否则......也许这些事件的时间已经改变(我认为这就是我所观察到的)。
我将在接下来的几天内观察这个,如果没有更好的表面,我会更深入地挖掘以确认我目前所知道的,并且没有更好的地方来解决行为的变化。 对不起,如果这令人困惑。 关于这些事件,我仍然不完全理解在幕后发生的很多事情。
干杯!

...是的, @borrull ,我同意。 如果苹果不再做出任何改变,那么这就是一个严重的定时炸弹,将真正导致不良新闻和指责。 我不喜欢将计时器作为解决方法(我宁愿围绕这些内置属性改进逻辑流程),但是如果我们不能依赖设置后的值更改,那么我们在哪里绘制线? 还有哪些我们不能信任的属性? 这是一个奇怪的。

@CleverCoder只想说声谢谢,你的补丁真的拯救了这一天!

@CleverCoder感谢您提供的解决方法。

我派生了一个解决方案,它使用来自 angular 的装饰器功能,并且没有修补 angular 源。

使用cssua,可以将此设置配置为仅在特定环境中使用。

    app.config(['$provide', ($provide) => {
        $provide.decorator('$browser', ['$delegate', ($delegate) => {
            var origUrl = $delegate.url;

            var pendingHref = null;
            var pendingHrefTimer = null;

            var newUrl = function (url, replace, state) {

                if (url) {
                    // setter
                    var result = origUrl(url, replace, state);

                    if (window.location.href != url) {

                        if (pendingHref != url) {
                            pendingHref = url;

                            if (pendingHrefTimer) clearTimeout(pendingHrefTimer);

                            pendingHrefTimer = setTimeout(function () {
                                if (window.location.href == pendingHref) {
                                    pendingHref = null;
                                }
                                pendingHrefTimer = null;
                            }, 0);
                        }
                    }

                    return result;
                } else {
                    // getter
                    if (pendingHref == window.location.href) {
                        pendingHref = null;
                    }

                    return pendingHref || origUrl(url, replace, state);
                }
            };

            $delegate.url = newUrl;

            return $delegate;
        }]);
    }]);

@CleverCoder见 #12635

@jd-carroll:这真的很有趣。 我可能会在今天晚些时候有时间的时候重新审视这个问题。 东西塞得满满当当。 这只会产生更多的神秘感,因为这似乎是一个单独的问题,不应导致位置延迟。* 值更新。

@realityfilter :有趣的是你提到了装饰器......我刚刚完成了使用 Angular 装饰器功能的实现。 好的!

大家好,
我只想补充一点,此修复程序在我们的代码中引入了一个易于修复的错误。

我们的模板有使​​用 href="#" 和 ng-click="someCall()" 的锚标签。 href 导致站点使用此修复程序转到 index.html。 删除 href 解决了这个问题。

我们的应用程序在 Ionic 中的后退按钮导航期间中断,它首先进入新视图,然后部分返回旧视图,然后在 IOS9 beta 上再次返回新视图 Ionic 的任何分辨率

与 iOS 9 beta 5 13A4325c、Angular 1.4.0(使用cordova-ios 3.9.1)相同的问题。 希望底层的 UIWebView 错误将得到修复!

同样的问题发生在 Angular v1.2.27

我已经将其追溯到 1.2.27 版本,该错误不在之前的 1.2.26 版本中。

具体来说,这次提交是罪魁祸首。

@damrbaby看起来我可以与它有关。

但是,它在 Mobile Safari 中使用最新版本的 angular 的事实清楚地表明,它必须对 iOS 9 上的 uiWebView 做一些事情。因此,他们在 Angular 源代码中所做的更改不一定是坏事。

@CleverCoder @realityfilter @jyc66我只想说谢谢你,你拯救了我的一天。

iOS9 GM Seed 上仍然存在问题,因此请让您的应用程序更新人员!

我可以确认,该问题仍然存在于 iOS9 GM (13A340)

所以这意味着 Apple 破坏了一些东西,我们必须再次更新我们的应用程序(其中一些已经几个月甚至一年多没有改变)以防止它们崩溃。 有道理:(。我宁愿让 Apple 在 iOS9 发布时修复它。在旧应用程序中使用最新的 Angular 版本也必然会破坏其他一些东西。

我非常怀疑 Angular 是唯一一个在 iOS9 上有问题的框架吗?

因此,来自 Ionic 团队的@adamdbradley@perrygovier@mhartington 一整天都在致力于修复,该修复适用于 Ionic 和普通的 Angular 应用程序。 目标是成为一个不需要修改 Angular 的插入式修复程序,并且(希望)适用于大多数 1.2+ Angular 版本。

这是我们当前的捆绑解决方案,它通过应用此补丁来装饰和修复$browser 。 注意:这是基于 Angular 1.4.3,是来自 Angular 的browser.js的“带有修复的克隆”: https :

我们还将补丁放在我们的 CDN 上。 我不建议将 CDN 文件用于生产,它只是在那里,所以现在更容易测试。

要测试它,请将此脚本标记放在您的 angular 或 ionic.bundle.js 文件下方:

<script src="https://code.ionicframework.com/patch/ios9-$browser-patch.js"></script>

此外,现在无论您是否在 iOS9 上运行,它都会应用该补丁。 这将很快得到修复,使其仅在 iOS 9 UIWebView 上运行。

在此处关注相应的 Ionic 问题: https :

大家好,

UI-sref 就像一个魅力,但 $state.go 打破了后退按钮动画
即使在应用此修复程序后,页面也会闪烁很多。

问候,
阿杰·辛格

2015 年 9 月 10 日星期四上午 6:23,Max Lynch [email protected]写道:

所以, @adamdbradley https://github.com/adamdbradley,@perrygovier
https://github.com/perrygovier和 @mhartington
来自 Ionic 团队的https://github.com/mhartington一直在工作
一整天都在修复适用于 Ionic 和普通 Angular 应用程序的问题
出色地。 目标是成为一个不需要修改的直接修复
Angular,并且(希望)适用于大多数 1.2+ Angular 版本。

这是我们当前的捆绑解决方案,它通过以下方式装饰和修复 $browser
应用这个补丁
https://github.com/angular/angular.js/issues/12241#issuecomment -130744518。
注意:这是基于 Angular 1.4.3,是一种“带有修复的克隆”
来自 Angular 的 browser.js:
https://github.com/driftyco/ionic/blob/ios9-patch/js/angular/service/decorators/ios9-browser-fix.js

我们还将补丁放在我们的 CDN 上。 我不建议使用 CDN 文件
对于生产,它只是在那里,所以现在更容易测试。

请测试一下,让我们知道它是怎么回事,谢谢。

要测试它,请将此脚本标记放在您的角度或
ionic.bundle.js 文件:

相关问题

WesleyKapow picture WesleyKapow  ·  3评论

ashclarke picture ashclarke  ·  3评论

ceymard picture ceymard  ·  3评论

visnup picture visnup  ·  3评论

kishanmundha picture kishanmundha  ·  3评论