Skip to main content
Ben Nadel at InVision In Real Life (IRL) 2019 (Phoenix, AZ) with: Salvatore D'Agostino
Ben Nadel at InVision In Real Life (IRL) 2019 (Phoenix, AZ) with: Salvatore D'Agostino

A Quick Look At How DOM Structure Affects Text Interpolation Watchers In AngularJS

By
Published in Comments (5)

I spend a lot of time thinking about how to improve the performance of my AngularJS apps. Not in a "premature optimization" way - more like in a "customers are complaining" kind of way. As such, I like to stop and noodle on any aspect of the code that may be leveraged for better performance. This morning, I wanted to quickly look at how your DOM (Document Object Model) structure affects text interpolation in AngularJS and how text interpolation affects the number of $watch() bindings on the page.

Run this demo in my JavaScript Demos project on GitHub.

When AngularJS compiles your HTML, it iterates over the DOM structure and looks for text nodes that contain the interpolation syntax markers. When it finds them, it computes an interpolation function and then connects the interpolation function to the current scope using a $watch() binding. This means that the structure of your DOM will have a direct affect on the number of overall $watch() bindings that are active on your current page.

To see this in action, I've created two micro AngularJS apps. Both of them produce the same exact output; but, the underlying DOM structure is different (in ways that might not seem relevant at first). For each, I'm going to alert() the number of active $watch() bindings on the page.

First, the "simple" DOM structure:

<!doctype html>
<html ng-app="Demo">
<head>
	<meta charset="utf-8" />

	<title>
		A Quick Look At How DOM Structure Affects Text Interpolation Watchers In AngularJS
	</title>
</head>
<body ng-controller="AppController">

	<h1>
		A Quick Look At How DOM Structure Affects Text Interpolation Watchers In AngularJS
	</h1>

	<p>
		<a href="javascript:alert('Watch%20Count:%20'+getWatchCount());void(0);">Get $watch Count</a>
	</p>

	<p>
		My friend, {{ friend.name }}, loves being a {{ friend.profession }}.
		I've only known her for {{ friend.friendship }} years; but, she's been doing
		it for {{ friend.workHistory }} years.
	</p>


	<!-- Load scripts. -->
	<script type="text/javascript" src="../../vendor/jquery/jquery-2.1.0.min.js"></script>
	<script type="text/javascript" src="../../vendor/angularjs/angular-1.2.22.min.js"></script>
	<script type="text/javascript" src="./get-watch-count.js"></script>
	<script type="text/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 ) {

				$scope.friend = {
					name: "Tricia",
					profession: "Stunt-man",
					friendship: 5,
					workHistory: 15
				};


			}
		);

	</script>

</body>
</html>

As you can see, all of the text interpolation is contained inside a single P-tag. And, when we alert the number of watchers, we get 1. That's because the entire P-tag can be compiled down and linked with a single interpolation function.

Now let's look at a more complex version:

<!doctype html>
<html ng-app="Demo">
<head>
	<meta charset="utf-8" />

	<title>
		A Quick Look At How DOM Structure Affects Text Interpolation Watchers In AngularJS
	</title>
</head>
<body ng-controller="AppController">

	<h1>
		A Quick Look At How DOM Structure Affects Text Interpolation Watchers In AngularJS
	</h1>

	<p>
		<a href="javascript:alert('Watch%20Count:%20'+getWatchCount());void(0);">Get $watch Count</a>
	</p>

	<p>
		My friend, <span class="name">{{ friend.name }}</span>,
		loves being a <span class="profession">{{ friend.profession }}</span>.

		<!--
			TODO: This is a really misleading variable name - it's not so much
			a friendship entity as it is just a duration for a friendship.
			Consider renaming.
		-->
		I've only known her for {{ friend.friendship }} years;

		<!-- TODO: Fix another horrible variable name. -->
		but, she's been doing it for {{ friend.workHistory }} years.
	</p>


	<!-- Load scripts. -->
	<script type="text/javascript" src="../../vendor/jquery/jquery-2.1.0.min.js"></script>
	<script type="text/javascript" src="../../vendor/angularjs/angular-1.2.22.min.js"></script>
	<script type="text/javascript" src="./get-watch-count.js"></script>
	<script type="text/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 ) {

				$scope.friend = {
					name: "Tricia",
					profession: "Stunt-man",
					friendship: 5,
					workHistory: 15
				};

			}
		);

	</script>

</body>
</html>

This time, we're still inside a single P-tag; but, there are nested structures. Not only are two of the variables inside Span tags but, there are HTML comments in between several of the other variables. Both of these characteristics affect the number of watch bindings. And, in fact, when we alert the number of watchers, we get 4.

By doing nothing but altering the structure of our DOM, we've quadrupled the number of watchers on the page. On its own, this isn't a problem. But, we do know that the number of watchers can affect AngularJS performance at scale. And, we also know that the complexity of the DOM tree can affect the performance of web pages in general. As such, it's just one more thing we can think about when we're trying to squeeze better performance out of our AngularJS applications.

Want to use code from this post? Check out the license.

Reader Comments

15,821 Comments

@Juri,

No problem - I use Camtasia for Mac (though they have a Windows version as well). It's been pretty cool. I don't do any editing or anything, but it has that capability as well.

5 Comments

Yea...and to be honest, it's a bit scary (especially to Angular newbies) that comments in the DOM reduce the performance of your app (although obviously you could have them stripe out by some preprocessor...but still).

15,821 Comments

@Juri,

It does seem a little strange; though, I think it's probably more interesting from a "technical" standpoint than from a "practical" standpoint. Or, at least one hopes.

1 Comments

Thanks for the video and the article. When all expressions are in <p>, what about the size of the expression being watched as opposed to number of watches? Is it the case that Angular creates watch for entire <p> instead of just {{ friend.name }} meaning that the whole, potentially long text will be stored in memory?
If thats the case then introducing <span> tags may help in delimiting the text size thats being watched.

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel