Optimizing AngularJS ng-repeat for Top Performance and Benchmarking

I have been conducting performance tests on AngularJS to determine its compatibility with our application. To assess and compare DOM creation speed, I developed a JSFiddle example where users can experiment with different numbers of items to create.

The goal is to showcase n random users sorted by their project, with content tailored to each project type and excluding secret users from display.

Here's the HTML:

<div ng-repeat="user in users | orderBy:'project'" post-repeat-directive
     ng-if="user.secretagent == false"
     class="user"
     ng-class="{male: (user.gender == 'm'), female: (user.gender != 'm')}"
     ng-switch="user.project">
    <h2>{{user.name}}</h2>
    Project: {{user.project}}
    <em ng-switch-when="fame">[fame]</em>
    <em ng-switch-when="idol">[idol]</em>
</div>

Javascript:

    angular.module('AngularBench', [])
    .config(['$compileProvider', function ($compileProvider) {
        $compileProvider.debugInfoEnabled(false);
    }])
    .controller("benchmarkController", ['$scope', 'TimeTracker', function($scope, TimeTracker) {
        $scope.result = undefined;
        $scope.users = [];

        $scope.benchmark = function(size) {
            TimeTracker.clockStartDate(size);

            var users = getUsers(size);

            $scope.users = users;

            $scope.$watch(
                    function () {   return TimeTracker.getDuration(); }, 
                    function(newVal, oldVal) { $scope.result = newVal; }, 
                    true
            );
        };
    }])
    .factory('TimeTracker', function() {
        var start, end, duration;

        return {
            clockStartDate: function() {
                start = Date.now();
            },
            clockEndDate: function() {
                end = Date.now();
                duration = (end - start) / 1000;
            },
            getDuration: function() {
                return duration;
            }
        };
    })
    .directive('postRepeatDirective', ['$timeout', 'TimeTracker', function($timeout, TimeTracker) {
        return function(scope, element, attrs) {
            if (scope.$last){
                $timeout(function(){
                    TimeTracker.clockEndDate();
                });
            }
        };
    }]);

function getUsers(size) {
    var users = [];
    for (var i=0; i<size; i++) {
        var user = {
            name: 'User ' + i,
            gender: Math.random() > 0.5 ? 'm' : 'w',
            project: Math.random() > 0.25 ? 'fame' : 'idol',
            secretagent: Math.random() > 0.95
        };
        users.push(user);
    }

    return users;
}

Despite this, I've observed a significant decline in performance as the number of items grows. Once it reaches around 2500 items, the performance becomes noticeably sluggish.

While I understand the usual recommendation of using pagination or auto-scrolling, my focus isn't on finding an alternative solution to handling large lists in ngRepeat. Do you have any ideas on how to enhance the performance?

Answer №1

If you are planning on using ng-repeat with a large number of items, it is essential to pay close attention and optimize each iteration for maximum efficiency.

One optimization strategy is to use a filter to hide users instead of utilizing ng-if. By filtering out the users that should not be displayed early on in the process, before sorting them, we can significantly speed up the rendering process:

ng-repeat="user in users | filter:usersFilter | orderBy:'project'"

This approach eliminates the need to create a new child scope with each iteration, as is the case with ng-if - resulting in faster performance. The same principle applies to ng-switch, which also creates its own child scope.

You can see the difference in performance by comparing this modified fiddle where ng-if and ng-switch have been removed: http://jsfiddle.net/2z2e33em/

The modified version produces the same output but executes much faster since two directives have been eliminated. This example demonstrates how minor changes like these can make a significant impact on overall performance (the modified fiddle was approximately 3 times faster in my testing).

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Display the Material UI Switch in an active state even when the "checked" value is set to false

While using Material UI Switches with Formik, I've encountered an issue. When I toggle the switch to 'enable,' it automatically sets the value in Formik to "true," and when I toggle it to 'disable,' it sets the value in Formik to " ...

Automating the recording of performance using Chrome DevTools' timeline feature

In my current endeavor, I am focused on creating valuable performance tests for an Angular application. For e2e testing, I rely on protractor and currently utilize protractor-perf. While this tool is effective in pinpointing performance issues, it falls ...

Submitting a nested JSON object in an AJAX request

When it comes to passing nested JSON through AJAX, the format of the sample request should be like this: { 'user': { 'email': email, 'password': password } } login(){ var email=document.getElementById(& ...

Leveraging ajax and jQuery for the implementation of PHP functionalities

UPDATE: Issue resolved. It turned out to be a simple mistake. The PHP file required one of those "?field=value" parameters in the URL, and that's what needed to be included in the data section. I needed to pass the input field value to the PHP file be ...

What is the best method to reset values in ngx-bootstrap date picker?

At the moment, it is only accepting the most recently selected values. To see a live demo, click here. ...

Is my data secure in Node.js RAM?

I have developed a web application that enables users to create personal pages using Express and Node.JS. Each page is represented as an object, allowing for the creation of new ones with the syntax: new privatePage(name, pswd). As a result, all passwords ...

The show-word-limit feature is malfunctioning on the element.eleme.io platform

After attempting to utilize the show-word-limit attribute of the input element, unfortunately the character count did not display. Below is the code snippet that was used: <el-input type="textarea" placeholder="Please input" ...

Is there a distinction between "muted" and "volume = 0.0"? Event listeners handle them in separate ways

I am a newcomer to coding and have encountered an issue that has me stumped. I am working on developing a small media player intended for use with the athletes I coach. The concept is to require them to listen to my commentary while watching game footage. ...

Triggering the JavaScript KeyUp() event for input values consisting of multiple digits

I'm currently working on a JavaScript project that involves displaying numbers from 1 to N based on user input. I am utilizing the keyup() event for this functionality. When the input field is cleared, it correctly displays nothing thanks to the empty ...

Trouble linking storage to database on Firebase with Vue.js

I'm currently diving into my Vue project integrating firebase to create locations with specialized images and data. I've been following a tutorial but it seems a bit outdated, especially when trying to connect Firebase storage with the database. ...

Problems with the navigation bar scrolling in Bootstrap

The project I'm currently working on is located at zarwanhashem.com If you'd like to see my previous question along with the code, you can check it out here: Bootstrap one page website theme formatting problems Although the selected answer help ...

The error message "Unknown provider: groupByFilterProvider <- groupByFilter error" is displayed when trying to use the angular.filter's groupBy filter

I am new to Angular and I'm trying to implement the `groupBy` filter from angular.filter but I'm having trouble including it in my project. I followed the first two steps outlined in the documentation at https://github.com/a8m/angular-filter#grou ...

Next.js Server Error: ReferenceError - 'window' is undefined in the application

I am currently in the process of integrating CleverTap into my Next.js application. I have followed the guidelines provided in the documentation Web SDK Quick Start Guide, however, I encountered the following issue: Server Error ReferenceError: window is ...

Tips for successfully including special characters in a query string using asp.net and jquery

Is there a way to pass %20 in the Query string without it being interpreted as a space in the code behind? I need to pass query strings using ASP.NET and also from JavaScript. Any suggestions on how to achieve this? Thank you in advance for your help. ...

What are some ways to maintain consistent audio levels on a jquery volume slider?

My html5 webpage features a slider and an audio track, but I am not using the sound tag property controls="controls". I want the slider to control the volume of the audio file. When I include the following code in the body tags, everything works perfectly: ...

I can't get the websocket to automatically reconnect unless I refresh the browser tab

Currently, I have a web server running websockets on an ESP8266. The operations are smooth on both the client and server sides, with data being sent and received. However, when the server side disconnects due to a power cycle or code upload, the client (Ch ...

Error: The expression `xmlDoc.load` returns a value of undefined, which is not an object

My current challenge involves loading an XML file using Javascript in IE, Firefox, and Safari. I have yet to find a function that works well across all three browsers. The load function I am currently using is similar to the one found in w3schools tutorial ...

How can I allow users to select multiple files with just one input?

Currently, I am able to retrieve a single file from a single input using the following code: $scope.$on("fileSelected", function (event, args) { $scope.$apply(function () { $scope.files.push(args.file); ...

What is the best way to capture data sent by Express within a functional component?

const Header = (props) => { const [ serverData, setServerData ] = useState({}); useEffect(() => { fetch('http://localhost:4001/api') .then(res => res.json()) .then((data) => { setServerData(data); ...

Swapping out a class or method throughout an entire TypeScript project

Currently, I am working on a software project built with TypeScript. This project relies on several third-party libraries that are imported through the package.json file. One such library includes a utility class, utilized by other classes within the same ...