Javascript AngularJS性能问题

Javascript AngularJS性能问题,javascript,html,performance,angularjs,lag,Javascript,Html,Performance,Angularjs,Lag,我正在构建一个复杂的angular应用程序,它可以无限滚动marsonry类的列和图像。我做了一项研究,并编写了自己的指令,为我呈现数据: angular.module('deepsy.flexgrid', []); angular.module('deepsy.flexgrid').directive('flexgrid', [ 'flexgridFactory', function initialize(flexgridFactory) { return

我正在构建一个复杂的angular应用程序,它可以无限滚动marsonry类的列和图像。我做了一项研究,并编写了自己的指令,为我呈现数据:

angular.module('deepsy.flexgrid', []);

angular.module('deepsy.flexgrid').directive('flexgrid', [

    'flexgridFactory',

    function initialize(flexgridFactory) {
        return flexgridFactory.create();
    }
]);


angular.module('deepsy.flexgrid').factory('flexgridFactory', [

    'FlexGrid',
    '$log',

    function initialize(FlexGrid, $log) {

        function Creator() {
            this.restrict = 'AE';

            this.scope = {
                'model': '=source',
                'opts': '=options'
            };

            this.$$grid = null;

            this.link = this.$$link.bind(this);
        }

        Creator.prototype.$$link = function $$link(scope, elem, attrs) {
            scope.itemTemplate = attrs.template;

            scope.mother = scope.$parent;

            scope.template = elem.html();
            elem.html('');

            this.$$grid = new FlexGrid(scope, elem);
        };

        return {
            create: function create() {
                return new Creator();
            }
        };
    }
]);

angular.module('deepsy.flexgrid').factory('FlexGrid', [

    '$compile',

    function($compile) {

        function FlexGrid(scope, elem) {
            this.scope = scope;
            this.elem = elem;
            this.state = null;
            this.counter = 0;
            this.id = Math.floor(Math.random() * 999);

            this.$getColumns();
            this.$createColumns();
            window.onresize = this.$watchSize.bind(this);


            this.scope.$watch(function() {
                return this.scope.model;
            }.bind(this), this.$applyData.bind(this), true);
        }

        FlexGrid.prototype.$getColumns = function() {
            var curr = null,
                width = document.body.clientWidth,
                min, max;

            for (var i in this.scope.opts.columns) {
                curr = this.scope.opts.columns[i];
                min = curr.min || 0;
                max = curr.max || 99999;

                if (min < width && width < max) {
                    this.state = curr;
                    return curr;
                }
            }
        };

        FlexGrid.prototype.$createColumns = function() {
            var output = [];
            for (var i = 0; i < this.state.columns; i++) {
                output.push('<div id="flexgrid_' + this.id + '_' + i + '" class="gridColumns ' + this.state.class + '"></div>');
            }
            this.elem.html(output.join(''));
        };

        FlexGrid.prototype.$watchSize = function() {
            var curr = this.state || {
                columns: 0
            };
            this.$getColumns();
            if (this.state.columns != curr.columns) {
                this.$createColumns();
                this.$fillData(0);
            }
        };

        FlexGrid.prototype.$applyData = function(newVal, oldVal) {

            var bindings = [],
                count = 0;

            oldVal.forEach(function(obj) {
                bindings.push(obj._id);
            });

            newVal.forEach(function(obj) {
                if (bindings.indexOf(obj._id) != -1) {
                    count++;
                }
            });

            if (count == oldVal.length && oldVal.length > 0) {
                this.$fillData(count);
                //  console.log('add');
            } else {
                this.$fillData(0);
                //  console.log('render');
            }
        };

        FlexGrid.prototype.$fillData = function(start) {
            var columns = this.state.columns,
                len = this.scope.model.length;

            if (start === 0) {
                this.$clearColumns(columns);
                this.counter = 0;
            }

            for (var i = start; i < len; i++) {
                $("#flexgrid_" + this.id + "_" + this.counter).append(this.$compile(this.scope.model[i]));

                if (this.counter++ === columns - 1)
                    this.counter = 0;
            }

            //$("img", this.elem).load(function(){
            //  $(this).parent().fadeIn(700);
            //});
        };

        FlexGrid.prototype.$compile = function(data) {
            var compiled = this.scope.template.replace(/\{\|[^\|\}]*\|\}/gmi, function(exp, val) {
                return data[exp.replace(/\|\}|\{\|/gmi, '')];
            });

            compiled = compiled.replace('src-image', 'src="' + data.image + '" dinimg');

            return compiled;
        };

        FlexGrid.prototype.$clearColumns = function(columns) {
            for (var j = 0; j < columns; j++) {
                $("#flexgrid_" + this.id + "_" + j).empty();
            }
        };

        return FlexGrid;
    }
]);
我发现我只有一个观察者!因此,观察者可能不是问题所在。通过这段代码,我实现了无限滚动。每个元素包含图像和文本。问题是,在获得超过200-250项后,我的UI开始滞后,即使我有一个观察者。我认为这可能是因为图像大小,但在Chrome控制台执行
$(“.item”).html(“”)并清除所有框的内容后,我的UI仍然不平滑。这个问题不是由太多的DOM元素引起的,因为除了指令呈现的div之外,我总共只得到了38个div。如何提高我的应用程序的性能


编辑:我还注意到一件奇怪的事情,即使我通过
$(“.item”)从DOM中删除所有元素(渲染后)。删除
,浏览器仍然使用300mb+RAM。

我会使用插件再次检查观察者计数,该插件有一个性能选项卡,您可以在其中查看所有手表


下面是如何使用chrome开发工具评测内存的摘要

堆分配配置文件:记录随时间的分配

  • 打开chrome开发工具
  • 打开配置文件选项卡
  • 单击堆分配配置文件
  • 单击开始
  • 执行将数据加载到网格中所需的操作
  • 单击“停止”
堆快照:记录实际分配的对象

  • 打开chrome开发工具
  • 打开配置文件选项卡
  • 单击堆快照
  • 单击“拍摄快照”
  • 执行将数据加载到网格中所需的操作
  • 再次单击左上角的“配置文件”
  • 单击“拍摄快照”
  • 运行
    $(“.item”).html(“”)
  • 再次单击左上角的“配置文件”
  • 单击“拍摄快照”
  • 单击左侧3个配置文件中的一个,然后查看实例
您还可以:

  • 单击左侧3个配置文件中的一个
  • 现在,在顶部栏中,将下拉列表设置为“Comparison”
  • 在“Comparison”选项旁边,选择要比较的快照

好的,很好。您是否尝试在
$(“.item”).html(“”)
前后拍摄堆分配配置文件(使用Chrome开发工具)和堆快照以查看剩余的对象类型?您能否简单解释一下我如何做到这一点?它是否有助于找到原因?@Deepsy,prb是什么?我们对图像进行了更多优化,以及删除无休止滚动中的第一个项目,因此现在更加平滑。
(function () { 
var root = $(document.getElementsByTagName('body'));
var watchers = [];

var f = function (element) {
    if (element.data().hasOwnProperty('$scope')) {
        angular.forEach(element.data().$scope.$$watchers, function (watcher) {
            watchers.push(watcher);
        });
    }

    angular.forEach(element.children(), function (childElement) {
        f($(childElement));
    });
};

f(root);

console.log(watchers.length);
})();