Forum Bugs

Serious performance degradation going from Prince 8.0 to 8.1

mikkelricky
We're using jQuery for selection DOM elements and the speed of this has seriouly degraded in Prince 8.1 (compared to Prince 8.0). I've tracked this down to jQuery converting a NodeList to an array by using Array.prototype.slice (see http://code.jquery.com/jquery-1.7.2.js, line 4855). This is much slower in Prince 8.1 than in Prince 8.0.

I've cooked up a pseudo scientific experiment for illustrating the performance issue (see attachment or test file below) and plotted the results in a couple of graphs [https://docs.google.com/spreadsheet/ccc?key=0Ap5BG-Ya1spxdHFIVTNGV05aaTAySG9ZY2pJVDRpOXc#gid=0].

The tests have been performed using the Mac version of Prince 8.0 and 8.1.

Best regards,
Mikkel

<?xml version="1.0" encoding="utf-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>DOM Speed</title>
  </head>
  <body>
	<pre id="output"></pre>
	<script type="text/javascript">/*<![CDATA[*/(function() {
var log = function() {
	var args = Array.prototype.slice.call(arguments, 0),
	line = args.join('\t'),
	container = document.getElementById('output');

	if (container.firstChild) {
		container.replaceChild(document.createTextNode(container.firstChild.nodeValue+'\n'+line), container.firstChild);
	} else {
		container.appendChild(document.createTextNode(line));
	}

	if ((typeof(console) != 'undefined') && (typeof(console.log) == 'function')) {
		;;; console.log(line);
	}
},

loop, i, elements, starttime, endtime, deltaT;

for (loop = 0; loop < 10; loop++) {
	// Create some elements
	for (i = 0; i < 100; i++) {
		document.body.appendChild(document.createElement('div'));
	}

	// Select the elements
	elements = document.getElementsByTagName('div');
	// When using jQuery for selecting elements, a NodeList is converted to an array by using Array.prototype.slice (http://code.jquery.com/jquery-1.7.2.js, line 4855).
	// This is extremely slow in Prince 8.1 compared to Prince 8.0
	starttime = new Date();
	elements = Array.prototype.slice.call(elements, 0);
	endtime = new Date();
	deltaT = endtime.getTime()-starttime.getTime();

	// Log number of elements, time used for getting array of HTMLElement and average time pr. element
	;;; log([ elements.length, deltaT, (elements.length > 0) ? (deltaT/elements.length) : '–' ].join('\t'));
}
}());/*]]>*/</script>
  </body>
</html>
  1. dom-speed.zip1.0 kB
mikeday
Thanks for the test case! Prince 8.1 is slower for NodeLists returned by getElementsByTagName() and similar DOM methods because it actually implements them correctly as "live lists", that update automatically as the document is updated. Prince 8.0 did not do this, leading to incompatibility with the way scripts run in web browsers. For example, if an element was removed from the document, it would not be removed from existing node lists.

Unfortunately, live node lists are much slower to access than static lists, so we will need to implement a caching optimisation to improve their performance.
mikkelricky
mikeday wrote:
Thanks for the test case! Prince 8.1 is slower for NodeLists returned by getElementsByTagName() and similar DOM methods because it actually implements them correctly as "live lists", that update automatically as the document is updated. Prince 8.0 did not do this, leading to incompatibility with the way scripts run in web browsers. For example, if an element was removed from the document, it would not be removed from existing node lists.

That's great and Prince should implement DOM methods correctly.
However, I'm not sure that live nodelists have solved more problems than they have generated, but let's not get into that right now. :-)

mikeday wrote:
Unfortunately, live node lists are much slower to access than static lists, so we will need to implement a caching optimisation to improve their performance.

Maybe you could reconsider implementing "querySelectorAll" [http://princexml.com/bb/viewtopic.php?f=3&t=17074&p=26651&hilit=queryselectorall#p26651] which returns a non-live NodeList [http://www.w3.org/TR/selectors-api/#queryselectorall]? If this method is implemented, jQuery will use it for getting element lists.
mikeday
Yes, live node lists were an unfortunate architectural choice for the JavaScript DOM, and we're stuck with them now. :)

I'll add the querySelector methods to the roadmap. We should be able to implement these or speed up getElementsByTagName, or hopefully both.
mikkelricky
Thanks a lot, Mike!
mikeday
Prince 9 is now available, and we have sped up getElementsByTagName considerably. Hopefully the performance should be acceptable now! :)
mikkelricky
Yes, the improvements are really impressive. Great job!

Thanks,
Mikkel