Ben Nadel: Using $scope.$digest() As A Performance Optimization In AngularJS

$apply / $digest scope test

by nickadeemus2002

HTML

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.min.js"></script>
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>
<div ng-app="Demo" ng-controller="AppController">

	<h1>
		Using $scope.$digest() As A Performance Optimization In AngularJS
	</h1>

	<!-- 
		Notice that both this P-tag and the next one both use ng-class to see CSS 
		classes based on the Model; however, the second P uses a child scope (created 
		by the bn-digest directive).
	-->
	<p 
		ng-mouseenter="setIsHot( true );"
		ng-mouseleave="setIsHot( false );"
		class="apply"
		ng-class="{ hot: isHot }">
		$apply()
	</p>

	<p 
		bn-digest 
		class="digest" 
		ng-class="{ hot: localIsHot }">
		$digest()
	</p>

	<p class="logging">
		<em>NOTE: Logging output to console.</em>
	</p>
</div>

CSS

a[ ng-click ] {
	cursor: pointer ;
	text-decoration: underline ;
}

p.apply,
p.digest {
	background-color: #FAFAFA ;
	border: 3px solid #CCCCCC ;
	cursor: default ;
	float: left ;
	height: 75px ;
	line-height: 75px ;
	text-align: center ;
	width: 200px ;
}

p.apply {
	margin-right: 30px ;
}

p.apply.hot,
p.digest.hot {
	background-color: #FFCCCC ;
	border-color: #FF3399 ;
}

p.logging {
	clear: both ;
}

JavaScript

// Create an application module for our demo.
		var app = angular.module( "Demo", [] );
		// -------------------------------------------------- //
		// -------------------------------------------------- //
		// I control the root of the application.
		app.controller(
			"AppController",
			function( $scope ) {
				// Setting up a watcher to mimic the high number of bindings that most 
				// applications will have. I will be called on every digest.
				$scope.$watch(
					function() {
						console.log( "Top-level digest 1." );
					}
				);
				// Setting up a watcher to mimic the high number of bindings that most 
				// applications will have. I will be called on every digest.
				$scope.$watch(
					function() {
						console.log( "Top-level digest 2." );
					}
				);
				// Setting up a watcher to mimic the high number of bindings that most 
				// applications will have. I will be called on every digest.
				$scope.$watch(
					function() {
						console.log( "Top-level digest 3." );
					}
				);
				// I determine if the target element is "hot" (for display purposes).
				$scope.isHot = false;
				// ---
				// PUBLIC METHODS.
				// ---
				// I set the new isHot property.
				$scope.setIsHot = function( newIsHot ) {
					$scope.isHot = newIsHot;
				};
			}
		);
		// -------------------------------------------------- //
		// -------------------------------------------------- //
		// I implement some mouse-interaction behavior without triggering digests at a 
		// higher level in the $scope chain.
		app.directive(
			"bnDigest",
			function() {
				// I bind the JavaScript events to the scope.
				function link( $scope, element, attributes ) {
					// I determine if the target element is hot.
					$scope.localIsHot = false;
					// I activate the element on mouse-enter.
					element.mouseenter(
						function() {                            
                            $scope.localIsHot = true;
							// NOTE: By calling the $digest() instead of the more...