範本在應用前必須先經過編譯,將我們提供的範本內容(包在<script type="x-jquery-tmpl">中的HTML片段、或直接傳入的HTML字串),變成一個"輸入資料物件、輸出HTML元素的Javascript函數",而所謂"套用範本",說穿了就是"一一傳入資料物件給範本函數,取得HTML元素"的過程。

將HTML範本內容編譯成範本函數的過程,涉及不少Regular Expression置換處理,RegExp固然威力強大,但運算起來也頗耗CPU,因此jQuery Templates內建了Cache機制,只在第一次套用時產生範本函數,之後會以jQuery.data()將範本函數保存在範本的容器HTML元素上(例如: <script type=”x-jquery-tmpl”>的<script>元素),省去每次重新編譯的無謂浪費。

但問題來了,若我們直接提供範本HTML字串作為.tmpl()參數,因缺乏容器HTML元素,使難以使用jQuery.data()暫存範本函數,享用Cache機制,得採行替代做法: .template()

透過$(“HTML範本字串").template("範本函數Cache名稱")$.template("範本函數Cache名稱", “HTML範本字串")將範本事先編譯保存,之後便能以$.tmpl(“範本函數Cache名稱”, 資料物件陣列)引用已編譯好的範本函數,省去每次重新編譯的功夫。另外,.template()不帶參數時傳回的就是範本函數,也可以當成.tmpl()的傳入參數,還有不少有趣的應用,之後再做介紹。

我寫了一小段範例程式原本想突顯預先編譯HTML範本字串的效能提升,並比較了.template()應用在<script type=”text/x-jquery-tmpl”>與HTML範本字串上的差別。由結果大致可看出<script>因原本就有Cache,差別不大;而HTML範本字串則有些許加快。不過可能因為範本還不夠複雜,引發的RegExp耗損不甚明顯,測試數字看不出明顯且可反覆驗證的穩定差別,不算是成功的效能測試,大家就當成應用.template()的示範參考好了。

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>jQuery Templates Lab 6 - HTML字串範本之預先編譯</title>
    <script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.4.4.js" 
        type="text/javascript"></script> 
    <script src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.js"
        type="text/javascript"></script>
    <script type="text/x-jquery-tmpl" id="tmplItem">
        <tr><td>${No}</td><td>${Name}</td><td>${Score}</td></tr>
        <tr><td>${No}</td><td>${Name}</td><td>${Score}</td></tr>
        <tr><td>${No}</td><td>${Name}</td><td>${Score}</td></tr>
        <tr><td>${No}</td><td>${Name}</td><td>${Score}</td></tr>
        <tr><td>${No}</td><td>${Name}</td><td>${Score}</td></tr>
        <tr><td>${No}</td><td>${Name}</td><td>${Score}</td></tr>
        <tr><td>${No}</td><td>${Name}</td><td>${Score}</td></tr>
        <tr><td>${No}</td><td>${Name}</td><td>${Score}</td></tr>
        <tr><td>${No}</td><td>${Name}</td><td>${Score}</td></tr>
        <tr><td>${No}</td><td>${Name}</td><td>${Score}</td></tr>
    </script>
    <script type="text/javascript">
//REF: http://blog.darkthread.net/blogs/darkthreadtw/archive/2009/06/16/js-stopwatch.aspx
        function darkStopWatch(timerName) {
            this.timerName = timerName;
            this.timerSt = new Date();
            this.resultQueue = [];
            this.tag = "Test";
        }
        darkStopWatch.prototype = {
            start: function (tag) {
                this.tag = tag;
                this.timerSt = new Date();
            },
            stop: function () {
                var ts = new Date() - this.timerSt;
                this.resultQueue.push(this.tag + " -> " + ts + "ms");
            },
            getRecord: function (clear) {
                var s = this.resultQueue.join("\n");
                if (clear) this.clear();
                return "StopWatch [" + this.timerName +
               "]\n====================\n" + s;
            },
            reset: function () {
                this.resultQueue = [];
            }
        }
    </script>
    <script type="text/javascript">
        $(function () {
            var data = [
                { No: 1, Name: "Jeffrey", Score: 59 },
                { No: 2, Name: "Darkthread", Score: 75 },
                { No: 3, Name: "Linda", Score: 96 }
            ];
 
            var testTimes = 100;
 
            var sw = new darkStopWatch("jQuery Templates plugin Test");
 
            //故意重複10次讓Template複雜一點,以突顯效能差異
            var ary = [];
            ary.push("<tbody>");
            for (var i = 0; i < 10; i++)
                ary.push(
                "<tr><td>${No}</td><td>${Name}</td><td>${Score}</td></tr>");
            ary.push("</tbody>");
            var tmplHtml = ary.join("\n");
 
            sw.start("<script>內嵌範本");
            for (var i = 1; i < testTimes; i++)
                $("#tmplItem").tmpl(data); //.appendTo("#tb");
            sw.stop();
 
            sw.start("<script>內嵌範本(編譯版)");
            $.template("compiledTmpl2", $("#tmplItem"));
            for (var i = 1; i < testTimes; i++)
                $.tmpl("compiledTmpl2", data); //.appendTo("#tb");
            sw.stop();
 
            sw.start("以HTML字串設定範本");
            for (var i = 1; i < testTimes; i++)
                $(tmplHtml).tmpl(data); //.appendTo("#tb");
            sw.stop();
 
            sw.start("以HTML字串設定範本(編譯版)");
            $.template("compiledTmpl1", tmplHtml);
            for (var i = 1; i < testTimes; i++)
                $.tmpl("compiledTmpl1", data); //.appendTo("#tb");
            sw.stop();
 
            alert(sw.getRecord());
 
            /* 測試結果範例
            StopWatch [jQuery Templates plugin Test]
            ====================
            <script>內嵌範本 -> 1112ms
            <script>內嵌範本(編譯版) -> 1111ms
            以HTML字串設定範本 -> 1484ms
            以HTML字串設定範本(編譯版) -> 886ms
            */
        });
    </script>
</head>
<body>
<table><tbody id="tb"></tbody></table>
</body>
</html>

Comments

Be the first to post a comment

Post a comment