为什么使用CryptoJS的哈希计算会在Angular中导致$rootScope:infdig错误

Why would a hash computation using CryptoJS cause a $rootScope:infdig error in Angular?

本文关键字:rootScope 错误 infdig Angular CryptoJS 哈希 计算 为什么      更新时间:2023-09-26

我有一个简单的页面,当有人在页面中键入字符串时,它会显示字符串的哈希值。我发现该页面有 JavaScript 错误

错误: [$rootScope:infdig] http://errors.angularjs.org/1.2.26/$rootScope/infdig?p0=10&p1=%5B%5B%22sha1...75651%2C1080464653%2C-772792499%5D%2C%5C%22sigBytes%5C%22%3A20%7D%22%5D%5D

该页面的一个非常简化的版本是

<html lang="en">
<head>
    <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/sha1.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
    <script>
        function MyCtrl($scope) {
            $scope.sha1 = function(pwd) {
                return CryptoJS.SHA1(pwd);
            };
        }
    </script>
</head>
<body>
    <div class="app" ng-app ng-controller="MyCtrl">
        <span ng-bind="sha1('bar')"></span>
    </div>
</body>
</html>

可作为 Plunker http://plnkr.co/edit/vmBtH8B2EKsdcfZVGlMH。

我试图在原始页面中做的是在有人在表单字段中键入时重新计算哈希,输入字段定义如下所示

<input id="password" ng-model="password" type="text" placeholder="Password">

ng-bind 确实是ng-bind="sha1(password)"的,但 Plunker 中的简单静态情况表现出相同的行为。

我认为 infdig 错误与太多的$digest周期有关,但我看不出这里会如何发生。看起来哈希计算触发了错误,因为从 sha1 函数返回静态字符串不会导致错误。

提供

ng-bind="sha1('bar')"会使摘要周期不稳定,每次sha1函数返回不同的对象(引用不同)并且您的摘要周期必须再次运行以稳定它,并且每个摘要周期再次计算ng-bind函数表达式,并继续直到达到最大限制集(10)。您还可以通过在范围方法中执行return []来轻松复制此问题。这只是将函数表达式绑定到ng-bind的不太好的做法的副作用,因为它运行每个摘要周期,如果使用的话,应该仔细评估。

一个简单的解决方案是在密码或任何其他触发器上绑定 ng-change/ng-blur 事件,只需将 ng-bind 绑定到属性而不是函数表达式。

angular.module('app',[])
.constant('Crypto', window.CryptoJS);
function MyCtrl($scope, Crypto) {
   $scope.encrypt = function() {
     $scope.encrypted = Crypto.SHA1($scope.password);
   };
 }
<html lang="en" ng-app="app">
<head>
  <script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/sha1.js"></script>
  <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
</head>
<body>
  <div class="app" ng-app ng-controller="MyCtrl">
    <input id="password" ng-model="password"  type="password" placeholder="Password" ng-change="encrypt()">
    <span ng-bind="encrypted"></span>
  </div>
</body>
</html>

为了更好地使用 DI,我将 crpto 放在一个常量中,并在需要的地方注入它。