Javascript 离子型(或角型)内存泄漏?

Javascript 离子型(或角型)内存泄漏?,javascript,angularjs,memory-leaks,ionic-framework,ng-repeat,Javascript,Angularjs,Memory Leaks,Ionic Framework,Ng Repeat,我对离子型和角型都是新手,所以我不确定这两者之间的问题究竟在哪里(如果有的话)。我似乎对ng repeat不清除内存有问题。我已经写了一个简单的例子来演示 index.html <html> <head> <meta charset="utf-8"> <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=dev

我对离子型和角型都是新手,所以我不确定这两者之间的问题究竟在哪里(如果有的话)。我似乎对ng repeat不清除内存有问题。我已经写了一个简单的例子来演示

index.html

<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
    <title></title>

    <link href="//code.ionicframework.com/nightly/css/ionic.css" rel="stylesheet">

    <!-- ionic/angularjs js -->
    <script src="//code.ionicframework.com/nightly/js/ionic.bundle.js"></script>
    <script src="cordova.js"></script>
    <script src="js/app.js"></script>

  </head>
  <body ng-app="starter">

    <ion-pane>
      <ion-header-bar class="bar-stable">
        <h1 class="title">Ionic Blank Starter</h1>
      </ion-header-bar>
      <ion-content ng-controller="CardsCtrl">
    <div ng-repeat="card in cards" on-tap="start(1000)">
        <img ng-src="{{card.image}}">
    </div>
      </ion-content>
    </ion-pane>
  </body>
</html>

离子空白起动器
js/app.js

angular.module('starter', ['ionic'])

.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if(window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if(window.StatusBar) {
      StatusBar.styleDefault();
    }
  });

}).controller('CardsCtrl', function($scope) {
    $scope.cards = [];


    var addCards = function(_num, y) {
        for (var x = 0; x < _num; x++) 
        {
            $scope.cards.push({
                image:"http://i.imgur.com/QR8mZAt.jpg?"+y
            }); 
        }
    }
    addCards(1, "new");

    var cardDestroyed = function(y) {

        //console.log("destroy");
        $scope.cards.splice(0, 1);
        addCards(1, y);
    };

    $scope.start = function(y){
        console.log("start");
        for (var x = 0; x < y; x++)
        {
            cardDestroyed(y);
        }
        console.log("stop");
    }
})
angular.module('starter',['ionic']))
.run(函数($ionicPlatform){
$ionicPlatform.ready(函数(){
//默认情况下隐藏附件栏(删除此选项可在键盘上方显示附件栏)
//表格输入)
if(window.cordova&&window.cordova.plugins.Keyboard){
插件键盘hideKeyboardAccessoryBar(真);
}
如果(窗口状态栏){
StatusBar.styleDefault();
}
});
}).controller('CardsCtrl',函数($scope){
$scope.cards=[];
var addCards=函数(_num,y){
对于(变量x=0;x<_num;x++)
{
$scope.cards.push({
图像:“http://i.imgur.com/QR8mZAt.jpg?“+y
}); 
}
}
添加卡(1,“新”);
变量=函数(y){
//控制台日志(“销毁”);
$scope.cards.拼接(0,1);
addCards(1,y);
};
$scope.start=函数(y){
控制台日志(“启动”);
对于(变量x=0;x
每次单击图片时,ng repeat使用的数组将删除一个元素并添加1000次。但内存中有东西粘住了,导致我的实际应用程序崩溃


有没有人能告诉我我是否做错了什么,或者它是否真的是一个bug?我浏览了github,没有看到与我所看到的相匹配的错误报告,一旦我确定不仅仅是我做错了什么,我就会去做一个报告。

如果你按照图表,你可以看到问题是发布的事件侦听器的数量。由于
$watch
在angular中的工作方式,从数组中删除一个元素然后添加一个新元素不会删除旧元素上的
$watch
,从而导致事件侦听器的数量继续无限增加

默认情况下,
$watch()
函数仅检查对象引用相等性。这意味着在每个
$digest
中,angular将检查新值和旧值是否是相同的“物理”对象。这意味着只有在实际更改基础对象引用时,vanilla
$watch()
语句才会调用其处理程序

解决这个问题有两种方法。首先,您可以使用Angular 1.3中提供的新Bind-Once语法。将
ng repeat
更改为
ng repeat=“card in::cards”
只会创建绑定,直到对表达式求值,然后销毁侦听器。这非常适合于您知道元素一旦被评估就永远不会改变的情况

另一种方法是对元素进行更积极的跟踪
ng repeat=“cards in cards track by$id”
将导致元素被
$id
字段跟踪,当DOM中不再存在具有唯一
$id
的对象时,angular将能够智能地删除侦听器

在时间轴中查看这两个选项,您将看到第一个选项Bind Once将花费更多时间,而没有侦听器,因为它将在求值后销毁侦听器,并且只生成新的侦听器以将新元素添加到DOM中。第二个选项将花费大部分时间在活动元素数量的侦听器上限,但会在删除元素时删除所有侦听器,并添加新的侦听器来替换它们

最后,如果您知道元素不会改变,只会被替换,那么绑定一次将更加有效;如果您的元素可以在添加和删除之间进行更改,则跟踪将更加灵活