Angular.js: ملخص لانهائي لتغيير الموقع على iOS 9 مع UIWebView (ليس في Safari / WKWebView)

تم إنشاؤها على ٣٠ يونيو ٢٠١٥  ·  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.
أنا قادر على إعادة الإنتاج على كل من iPad Air 2 و iPad من الجيل الرابع مع iOS 9 beta 2.
أدرك أنها ربما تكون مشكلة في نظام التشغيل iOS ، ولكن قد لا يزال الأمر يستحق التحقيق.

iOS $location bug

التعليق الأكثر فائدة

حصلت على مزيد من المعلومات حول هذا الأمر. لقد أجريت تغييرًا في Angular فيما يتعلق بالموقع.
في جزء "تحديث المتصفح" ، قمت بتغيير $ rootScope. $ EvalAsync إلى $ rootScope. $ applyAsync.

يبدو أن الطريقتين تفعلان الشيء نفسه تمامًا. لا يصبح الاختلاف واضحًا حتى تنظر إلى التنفيذ الفعلي لـ $ Digger. عندما ينفذ AngularJS ملخصًا ، فإنه يمشي في شجرة النطاق وينفذ روابط $ watch () حتى لا يتم إنتاج المزيد من البيانات المتسخة. أثناء دورة الحياة هذه ، يتم مسح كل من قائمة انتظار $ applyAsync () وقائمة انتظار $ EvalAsync () ؛ لكن هذا يحدث في مكانين مختلفين للغاية.

يتم مسح قائمة انتظار $ applyAsync () فقط في الجزء العلوي من ملخص $ قبل أن يبدأ AngularJS في التحقق من البيانات المتسخة. على هذا النحو ، سيتم مسح قائمة انتظار $ applyAsync () ، على الأكثر ، مرة واحدة خلال ملخص $ ولن يتم مسحها إلا إذا تم ملء قائمة الانتظار بالفعل قبل بدء الملخص $.

من ناحية أخرى ، يتم مسح قائمة انتظار $ EvalAsync () في الجزء العلوي من حلقة while-loop التي تنفذ "الاختيار القذر" داخل ملخص $. هذا يعني أن أي تعبير يضاف إلى قائمة انتظار $ EvalAsync () أثناء الملخص سيتم تنفيذه في وقت لاحق ضمن نفس الملخص.

لجعل هذا الاختلاف أكثر واقعية ، فهذا يعني أن التعبيرات غير المتزامنة المضافة بواسطة $ EvalAsync () من داخل ربط $ watch () سيتم تنفيذها في نفس الملخص. سيتم تنفيذ التعبيرات غير المتزامنة المضافة بواسطة $ applyAsync () من داخل ربط $ watch () في وقت لاحق (حوالي 10 مللي ثانية).

آمل أن يساعد هذا بالفعل بعضًا منكم :-).


// 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 لا يزال يطرح استثناءات infdig على iOS 9 beta 3.

أتلقى نفس الخطأ مع ios9 public beta (13A4293g)

خطأ: تم بلوغ عدد مرات التكرار [$
أطلق المراقبون في آخر 5 تكرارات: []
http://errors.angularjs.org/1.3.13/ $ rootScope / infdig؟ p0 = 10 & p1 =٪ 5B٪ 5D
ملف: ///Users/mac5/Library/Developer/CoreSimulator/Devices/749DE7E3-D93F-47F9-A1FC-E3D54A1CCEEE/data/Containers/Bundle/Application/9B5EE368-F2A0-4C99-807B-EAB24. /lib/ionic/js/ionic.bundle.js:8762:32
$ Digest
$ application
ملف: ///Users/mac5/Library/Developer/CoreSimulator/Devices/749DE7E3-D93F-47F9-A1FC-E3D54A1CCEEE/data/Containers/Bundle/Application/9B5EE368-F2A0-4C99-807B-EAB24. /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-80724.app /www/lib/ionic/js/ionic.bundle.js:11713:25
dispatchEvent @ [الرمز الأصلي]
TriggerMouseEvent @ file : ///Users/mac5/Library/Developer/CoreSimulator/Devices/749DE7E3-D93F-47F9-A1FC-E3D54A1CCEEE/data/Containers/Bundle/Application/9B5EE368-F2A79-4C99B2458h /www/lib/ionic/js/ionic.bundle.js:2863:20
tapClick @ file : ///Users/mac5/Library/Developer/CoreSimulator/Devices/749DE7E3-D93F-47F9-A1FC-E3D54A1CCEEE/data/Containers/Bundle/Application/9B5EE368-F2A0-4C99-807BE-58EA /www/lib/ionic/js/ionic.bundle.js:2852:20
tapTouchEnd @ file : ///Users/mac5/Library/Developer/CoreSimulator/Devices/749DE7E3-D93F-47F9-A1FC-E3D54A1CCEEE/data/Containers/Bundle/Application/9B5EE368-F2A0-4C99-247B58 /www/lib/ionic/js/ionic.bundle.js:2975:13

نتلقى هذا الخطأ أيضًا في الإصدار التجريبي 3 العام من iOS 9 من خلال تطبيق Angular الخاص بنا. لا يحدث في نظام التشغيل 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

نعم ، نشهد نفس المشكلة أيضًا حتى مع جهاز توجيه واجهة المستخدم الزاوي. هل لدى أي شخص عمل صالح حول هذه المشكلة في الوقت الحالي؟

رؤية نفس المشكلة في uiWebView على أحدث إصدار من iOS9.

هل لدى أي شخص أي تحديثات حول هذه المسألة؟

وما زالت هذه المسألة. إعادة الفتح

يبدو أنه مشكلة iOS. هل هذا تعقب على webkit في مكان ما؟

+1

+1

كذلك هنا. يعمل تطبيق كوردوفا بشكل جيد إذا كان يعمل كويب على iPad Safari ، ولكن الخلاصة اللانهائية تحدث إذا تم تشغيله كتطبيق كوردوفا (UIWebView)

بالضبط نفس المشكلات مثل borrull ! جربت بالفعل WKWebView ومن ثم فإن المشكلة غير موجودة. لكن لا يمكننا استخدام WKWebView لأننا نحتاج إلى خدمة الملفات المحلية (ولا نريد تشغيل خادم محلي في تطبيقنا) وملفات تعريف الارتباط. لذلك يجب أن تفعل شيئًا مع UIWebView بالاشتراك مع Cordova / Mobile Safari على نظام التشغيل iOS 9. أقوم حاليًا بتصحيح أخطاء $ locationWatch في Angular لأنني أرى أن تطبيقنا يريد الانتقال إلى موقع مختلف عدة مرات ثم (بعد 10 مرات ) تم طرح خطأ الملخص.

نفس المشكلة هنا على iOS9 béta4
حلقة هضم $ لانهائية زاويّة ؛ (

+1 ، فقط في UIWebView ، وليس في WKWebView ولكن يمكننا فقط استخدام UIWebView في تطبيق كوردوفا.

+1

إذا كانت هذه مشكلة خاصة بنظام iOS ، فالرجاء فتح مشكلة في أداة تعقب مشكلات webkit وتقديم عرض توضيحي! لن يغير زر 1+ هنا أي شيء على الأرجح ، لأنه يبدو حقًا خطأً في المتصفح.

هل أبلغ أحدهم شركة Apple عن هذا الخطأ للتحقيق فيه؟

لقد أبلغت شركة آبل عن هذا الخطأ. ولكن ربما يجب عليك جميعًا أن تفعل الشيء نفسه لجذب انتباههم إلى الخطأ.

هل يمكنك أن تعطينا رابطًا حتى نتمكن من إجراء 1+؟

إنه موجود في حسابنا الشخصي على Apple عبر مراسل الخطأ .. لذا لا يوجد رابط عام ؛ (

هل يمكنك نشره على openradar ومشاركة معرف rdar حتى نتمكن من خداعه!

نفس الشيء على iOS9 béta 5:
يعمل على الجوال سفاري
يعمل على WKWebview الذي لا يمكننا استخدامه لأنه لا يمكنه خدمة الملفات المحلية ولا يدعم NSProtocol
لا يعمل على UIWebView

نفس الشيء هنا على IOS 9 Beta 5

لقد قدمت خطأ مع Apple أيضًا. رابط Open Radar هو: https://openradar.appspot.com/22186109 (من المفترض أن يساعد ذلك الأشخاص الكسالى على الإبلاغ عن خطأ). يرجى ترك تعليقات إذا كان بإمكانك تحسين صياغة / شرح الخطأ ؛-) يمكنك تنزيل مشروع Xcode لإرفاقه مع ملف الخطأ على بطاقة Open Radar (بفضل santaslow لـ JS في OP)

لقد قمت بإنشاء نسخة من نفس مشروع Xcode (منborrull) ولكن باستخدام ui-router بدلاً من ng-route. بالضبط نفس المشكلة. للأشخاص المهتمين ، يمكنك العثور على المشروع هنا: http://s000.tinyupload.com/index.php؟file_id=87281871603760127355

نحن نرى أيضًا هذه المشكلة. لقد تمكنت من مطاردة المشكلة لكون هذا الموقع. * لا يتم تحديث الخصائص على الفور عندما تكون الزاوية في المزيج. إذا حاولت تعيين قيمة إلى location.hash (مثل ما يتم إجراؤه خلف خدمة الموقع) ، فقم بقراءتها على الفور مرة أخرى ، فلن تتغير القيمة. يبدو أن هناك بعض الآثار الجانبية التي تحدث نتيجة لمعالجات jqlite المرتبطة بأحداث popstate و hashchanged.

سأحاول وتحميل عينة عندما أكون على جهاز كمبيوتر.

+1

CleverCoder أي تحديثات على العينة؟

سيتعين علي إنهاء حالة repro في الصباح ، لأن الرمز كما كنت مقيّدًا طوال عطلة نهاية الأسبوع. شكرا على التنبيه! نظرًا لأن نظام التشغيل 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 صحيحة بعد دوران حلقة التشغيل. يمكن لـ Angular حل هذه المشكلة بسهولة عن طريق تأخير location.hash إلى setTimeout (... ، 0). أعتقد أن هذا سيكون حوالي 2 تغيير على angular.js / src / ng / location.js.

hober حاول المهلة بزاوية كالتالي:

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

لذلك أضفت setTimout حول طريقة setBrowserUrlWithFallback لكنها لم تحل المشكلة.

إليك حالة اختبار مخفضة لا تعتمد على Angular ، وهذا يوضح الحل البديل. كيفية تنفيذ الحل في Angular غير واضح بالنسبة لي. https://gist.github.com/hober/a29b6c28ac1744c800dd

حصلت على مزيد من المعلومات حول هذا الأمر. لقد أجريت تغييرًا في Angular فيما يتعلق بالموقع.
في جزء "تحديث المتصفح" ، قمت بتغيير $ rootScope. $ EvalAsync إلى $ rootScope. $ applyAsync.

يبدو أن الطريقتين تفعلان الشيء نفسه تمامًا. لا يصبح الاختلاف واضحًا حتى تنظر إلى التنفيذ الفعلي لـ $ Digger. عندما ينفذ AngularJS ملخصًا ، فإنه يمشي في شجرة النطاق وينفذ روابط $ watch () حتى لا يتم إنتاج المزيد من البيانات المتسخة. أثناء دورة الحياة هذه ، يتم مسح كل من قائمة انتظار $ applyAsync () وقائمة انتظار $ EvalAsync () ؛ لكن هذا يحدث في مكانين مختلفين للغاية.

يتم مسح قائمة انتظار $ applyAsync () فقط في الجزء العلوي من ملخص $ قبل أن يبدأ AngularJS في التحقق من البيانات المتسخة. على هذا النحو ، سيتم مسح قائمة انتظار $ applyAsync () ، على الأكثر ، مرة واحدة خلال ملخص $ ولن يتم مسحها إلا إذا تم ملء قائمة الانتظار بالفعل قبل بدء الملخص $.

من ناحية أخرى ، يتم مسح قائمة انتظار $ EvalAsync () في الجزء العلوي من حلقة while-loop التي تنفذ "الاختيار القذر" داخل ملخص $. هذا يعني أن أي تعبير يضاف إلى قائمة انتظار $ EvalAsync () أثناء الملخص سيتم تنفيذه في وقت لاحق ضمن نفس الملخص.

لجعل هذا الاختلاف أكثر واقعية ، فهذا يعني أن التعبيرات غير المتزامنة المضافة بواسطة $ EvalAsync () من داخل ربط $ watch () سيتم تنفيذها في نفس الملخص. سيتم تنفيذ التعبيرات غير المتزامنة المضافة بواسطة $ applyAsync () من داخل ربط $ watch () في وقت لاحق (حوالي 10 مللي ثانية).

آمل أن يساعد هذا بالفعل بعضًا منكم :-).


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

إليك طريقة أخرى. لست على دراية بقاعدة الكود الزاوي ، لكن المنطق يبدو منطقيًا. تعتمد وظيفة عنوان url (...) في المتصفح حاليًا على الموقع. href يعيد عنوان URL الصحيح على الفور. نظرًا لاستدعاء هذه الطريقة في نفس حلقة التشغيل ، ضمن دورة تثبيت $ Digest ، فإنها تستمر في الحصول على عنوان URL القديم. يعمل هذا التصحيح على الاستفادة من "waitingHref" لتتبع المهمة وإرجاع تلك القيمة بدلاً من ذلك ، إذا تم تعيينها. بمجرد محاذاة القيمة مع location.href ، يتم مسح القيمة المعلقة. أثناء مجموعة عنوان url ، يتم تعيين عداد الوقت بـ 0 مللي ثانية للقبض على الحالة التي لا يتم فيها استدعاء عنوان url (). إنه ليس مثاليًا ، لكن المنطق يبدو أنه يعمل. هذا بشكل أساسي للنظر في نهج بديل لا يؤدي إلى تأخير في الأداء. هذا مبني على Angular tag 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:

تضمين التغريدة
سيكون رائعًا إذا قمت بإجراء طلب سحب مع هذا الفريق الزاوي.

viattik سأفاجئني نوعًا ما إذا اعتمد الفريق الزاوي حلاً بديلاً لـ UIWebView على iOS9 نظرًا لأن الخطأ موجود في UIWebView (Apple) نفسها. لكن يمكنك دائمًا المحاولة ...

Raftheunis87
هناك الكثير من الأخطاء في المتصفحات المختلفة والكثير من الحلول لتلك الأخطاء في الكود الزاوي.
على الرغم من أنها لا تدعم UIWebView رسميًا ، إلا أنه سيتم كسر الكثير من التطبيقات المختلطة وسيكون استخدام الزاوية مستحيلًا في التطبيقات المختلطة في أحدث نظام تشغيل iOS حتى تقوم Apple بإصلاح هذا الخطأ. وهذه مشكلة كبيرة جدًا أود أن أقول.
لذلك سأجربها.

viattik أتفق تماما. راجع للشغل: أبلغتنا Apple أنه من غير المحتمل أن يصلحوا خطأ UIWebView. لذا بالفعل: جربها ؛-)

أيها الناس ، إذا كان بإمكانك نشر هذا على أنه خطأ في webkit ، بشكل مثالي مع حالة repro ، فسأتابع مع بعض جهات الاتصال الخاصة بنا على جانب WebKit. https://bugs.webkit.org/

تضمين التغريدة
لست متأكدًا مما إذا كان خطأ في webkit. لأنه يحدث فقط في UIWebView على iOS9. يعمل Safari على iOS9 بشكل جيد.

@ raftheunis87 شكرا لاقتراحات التعليمات البرمجية الخاصة بك ، عملت بشكل مثالي

@ raftheunis87CleverCoder هو عبتي وسيلة للعمل مع الأيونية-الزاوي؟ يمكنك أن تكون أكثر تحديدا؟

abrahamrkj ليس لدي أي خبرة مع الأيونات. لكن هل تخصيصاتهم في الزاوية عند استخدام الأيونية؟ وإلا سأقول أن نفس الإصلاح سيعمل مع الزاوية الأيونية ...

@ raftheunis87 https://github.com/driftyco/ionic/tree/master/js هذه هي الزاوية التي يستخدمونها.

CleverCoder +1 لطلب السحب. أتفق مع viattik على أن هذه مشكلة مهمة لأنها ستؤدي إلى كسر الكثير من التطبيقات المختلطة.

قد يكون طلب السحب في المستقبل القريب ، على الرغم من أنني متردد لأنني لست قريبًا من قاعدة الكود الزاوي مثل الآخرين. سأعيد النظر في الحل قريبًا وسأحاول جعله مضادًا للرصاص. يبدو من الغريب ألا تتغير خاصية على الكائن window.location "على الفور". في الاختبارات التي أجريتها ، لاحظت أن التغيير ظل ثابتًا طالما لم تكن خطافات حدث "popstate" و "hashchange" في مكانها ، مما دفعني إلى الاعتقاد بأن سبب التغيير المؤجل قد يكون فعلًا شيء آخر .. ربما تغير توقيت تلك الأحداث (أعتقد أن هذا ما كنت ألاحظه).
سأشاهد هذا خلال الأيام القليلة القادمة ، وإذا لم يظهر شيء أفضل ، فسأحفر أعمق قليلاً لتأكيد ما أعرفه حتى الآن ، وأنه لا يوجد مكان أفضل لمعالجة التغيير في السلوك. اسف اذا كان هذا مربك. هناك الكثير من الأمور التي ما زلت لا أفهمها تمامًا فيما يتعلق بتلك الأحداث.
هتافات!

... ونعم ، borrull ، أوافق. إذا لم تقم Apple بإجراء المزيد من التغييرات ، فهذه قنبلة موقوتة خطيرة ستؤدي حقًا إلى الضغط السيئ وتوجيه الإصبع. لست معجبًا بالمؤقتات كحل بديل (أفضل تحسين التدفق المنطقي حول هذه الخصائص المضمنة) ، ولكن إذا لم نستطع الاعتماد على تغيير القيمة بمجرد تعيينها ، فأين نرسم خط؟ ما هي الخصائص الأخرى التي لا يمكننا الوثوق بها؟ إنه أمر غريب.

CleverCoder أردت فقط أن أقول شكرًا ، لقد أنقذ التصحيح الخاص بك اليوم حقًا!

CleverCoder شكرًا على الحل البديل.

لقد اشتقت حلاً يستخدم ميزة الزخرفة من الزاوي ويأتي بدون تصحيح المصدر الزاوي.

باستخدام 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 انظر #

@ jd-carroll: هذا مثير للاهتمام حقًا. قد أعيد النظر في هذا لاحقًا اليوم عندما يكون لدي وقت. غارقة جدا مع الاشياء. هذا فقط يخلق المزيد من الغموض ، لأن ذلك يبدو وكأنه مشكلة منفصلة لا ينبغي أن تؤدي إلى تأخير في الموقع. * تحديث القيم.

realityfilter : من المضحك أن تذكر مصمم الديكور ... لقد انتهيت للتو من تنفيذ شيء ما باستخدام وظيفة Angular decorator. لطيف!

مرحبا جميعا،
أردت فقط أن أضيف أن هذا الإصلاح تسبب في وجود خطأ في التعليمات البرمجية الخاصة بنا كان من السهل إصلاحه.

تحتوي قوالبنا على علامات ربط تستخدم 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 يبدو أنه يمكن أن أفعل شيئًا به.

لكن حقيقة أنه يعمل مع أحدث إصدار من Angular في Mobile Safari توضح أنه يجب أن يفعل شيئًا ما باستخدام uiWebView على iOS 9. لذا فإن التغيير الذي أجروه في شفرة المصدر Angular ليس بالضرورة أمرًا سيئًا.

CleverCoderrealityfilter @ jyc66 أردت فقط أن أقول شكرا لكم، وحفظته للتو بلدي اليوم.

لا تزال المشكلة موجودة في iOS9 GM Seed لذا احصل على تطبيقاتك المحدثة!

أستطيع أن أؤكد أن المشكلة لا تزال موجودة في iOS9 GM (13A340)

هذا يعني أن Apple كسرت شيئًا ما وعلينا تحديث تطبيقاتنا مرة أخرى (بعضها لم يتغير منذ شهور أو حتى أكثر من عام) لمنعها من الانهيار. من المنطقي :(. أفضل أن أجعل Apple تصلحه لإطلاق iOS9. الانتقال إلى أحدث إصدار من Angular في تطبيق قديم لا بد أن يكسر بعض الأشياء الأخرى أيضًا.

أشك بشدة في أن Angular هو الإطار الوحيد الذي يواجه مشكلات مع iOS9؟

لذا ، فإن adamdbradley و perrygovier و

هذا هو الحل المجمّع الحالي الذي يزين ويصلح $browser خلال تطبيق هذا التصحيح . ملاحظة: يعتمد هذا على Angular 1.4.3 وهو نوع من "استنساخ مع إصلاحات" browser.js من Angular Proper: https://github.com/driftyco/ionic/blob/ios9-patch/js /angular/service/decorators/ios9-browser-fix.js

وضعنا الرقعة أيضًا على شبكة توصيل المحتوى الخاصة بنا. لا أوصي باستخدام ملف CDN للإنتاج ، فهو موجود فقط لذا من السهل اختباره الآن.

لاختبارها ، ضع علامة البرنامج النصي هذه أسفل ملف angular أو ionic.bundle.js:

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

أيضًا ، في الوقت الحالي ، يتم تطبيق التصحيح سواء كنت تعمل على iOS9 أم لا. سيتم إصلاح ذلك قريبًا بحيث يتم تشغيله فقط على iOS 9 UIWebView.

اتبع المشكلة الأيونية المقابلة هنا: https://github.com/driftyco/ionic/issues/4082#issuecomment -139079725

أهلا بكم،

يعمل UI-sref مثل السحر ولكن $ state.go يكسر حركة الزر الخلفي
وتومض الصفحة كثيرًا حتى بعد تطبيق هذا الإصلاح.

يعتبر،
اجاي سينغ

في الخميس ، 10 سبتمبر 2015 ، الساعة 6:23 صباحًا ، كتب Max Lynch [email protected] :

لذا ، adamdbradley https://github.com/adamdbradley،perrygovier
https://github.com/perrygovier وmhartington
https://github.com/mhartington من فريق Ionic يعمل
طوال اليوم على الإصلاح الذي سيعمل مع Ionic وتطبيقات Angular العادية مثل
نحن سوف. الهدف هو أن يكون إصلاحًا بدون انتظار ولا يتطلب تعديلًا
Angular ، وسوف يعمل (نأمل) عبر أكثر من 1.2+ إصدارات Angular.

هذا هو الحل المجمع الحالي الذي يزين ويصلح متصفح $ بواسطة
تطبيق هذا التصحيح
https://github.com/angular/angular.js/issues/12241#issuecomment -130744518.
ملاحظة: هذا مبني على Angular 1.4.3 وهو نوع من "استنساخ مع إصلاحات"
browser.js من الزاوية المناسبة:
https://github.com/driftyco/ionic/blob/ios9-patch/js/angular/service/decorators/ios9-browser-fix.js

وضعنا الرقعة أيضًا على شبكة توصيل المحتوى الخاصة بنا. لا أوصي باستخدام ملف CDN
للإنتاج ، فهو موجود فقط ، لذا من السهل اختباره الآن.

يرجى اختباره وإخبارنا كيف ستسير الامور ، شكرا.

لاختبارها ، ضع علامة البرنامج النصي هذه أسفل الزاوية أو
ملف ionic.bundle.js: