JavaScriptパフォーマンス改善(2) document.getElementById()も遅い!

JavaScriptパフォーマンス改善(2) document.getElementById(要素ID)も、でら遅いじゃん!

【調査対象】

ブラウザ:
IEFirefox
遅いJavaScriptコード:
document.getElementById(id)
改善速度:
IEは数百倍(200〜2000倍以上),Firefoxは8倍程度
改善方法:
最初にすべての要素をキャッシュしておき、キャッシュから要素を取得する。


【Sample Code】

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Cache-Control" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<title>JavaScript performance test</title>
<script type="text/javascript">

// timer
var TS = {
	_time: (new Date()).getTime(),
	_log: [],
	init: function() {
		TS._time = (new Date()).getTime();
	},
	record: function(in_title) {
		var nowTime = (new Date()).getTime();
		var intervalTime = nowTime - TS._time;
		TS._log.push(in_title + " : " + intervalTime + "ms");
		TS._time = (new Date()).getTime();
		return intervalTime;
	},
	getRecordList: function() {
		var result = TS._log;
		TS._log = [];
		return result;
	}
}

// element cache
var FormElementCache = {};

// html initialize
window.onload = function() {
	var formBody = document.getElementById("formBody");
	var elementType = [
		{tagName: "INPUT", type: "text"},
		{tagName: "INPUT", type: "radio"},
		{tagName: "INPUT", type: "checkbox"},
		{tagName: "INPUT", type: "button"},
		{tagName: "INPUT", type: "hidden"},
		{tagName: "TEXTAREA", type: ""},
		{tagName: "SELECT", type: ""}
	];
	for (var loop = 0; loop < 2000; loop++) {
		var type = loop % elementType.length;
		var e = document.createElement(elementType[type].tagName);
		if (elementType[type].type) {
			e.type = elementType[type].type;
		}
		e.id = "test" + loop;
		e.name = "test" + loop;
		e.value = 1 + loop;
		formBody.appendChild(e);
	}
}

// test program
function performanceTest() {

	TS.init();

	var ids = [];
	var felements = document.form1.elements;
	for (var fi = 0, lenfi = felements.length; fi < lenfi; fi++) {
		var e = felements[fi];
		if (e.id) {
			FormElementCache[e.id] = e;
			ids.push(e.id);
		}
	}
	TS.record("form1.elements cached. count=" + ids.length);

	for (var loop=0; loop < 1; loop++) {
		for (var i = 0, len = ids.length; i < len; i++) {
			var e = document.getElementById(ids[i]);
		}
	}
	TS.record("document.getElementById[id] readed (" + loop + " loop)");

	for (var loop=0; loop < 100; loop++) {
		for (var i = 0, len = ids.length; i < len; i++) {
			var e = FormElementCache[ids[i]];
		}
	}
	TS.record("FormElementCache[id] readed (" + loop + " loop)");

	alert(TS.getRecordList().join("\n"));

}

</script>
</head>
<body>
<dl>
<dt>JavaScript Performance Test</dt>
<dd>document.getElementById(id) VS FormElementCache[id]</dd>
</dl>
<input type="button" value="Start!" onclick="performanceTest();" /><br />
<form name="form1">
<div id="formBody"></div>
</form>
</body>
</html>