Templalienを実際に使ってみる
Templalien jQueryを使用したテンプレートエンジンもどき - 文殊堂を実際に使ってみます。
<html lang="ja"> <head> <title>Templalien</title> <link type="text/css" rel="stylesheet" media="screen, projection" href="http://assets2.twitter.com/stylesheets/screen.css"/> <script src="http://jqueryjs.googlecode.com/files/jquery-1.2.6.js" type="text/javascript"></script> <script type="text/javascript"> <!-- function Templalien(template){ this._template = jQuery(template); }; Templalien.prototype.merge = function(context){ var template = this._template.clone(); jQuery.each(context,function(selector,func){ var elem = selector ? template.find(selector) : template; func(elem); }); return template; }; $(function(){ // Templalienインスタンスを生成して時間を計る var initStarted = Date.now(); var entry = new Templalien([ '<tr class="hentry_hover">' ,' <td class="thumb vcard author">' ,' <a class="url"><img id="profile-image" class="photo fn"/></a>' ,' <a class="anchor"></a>' ,' </td>' ,' <td class="content">' ,' <strong><a></a></strong>' ,' <span class="entry-content"></span>' ,' <span class="meta entry-meta">' ,' <a rel="bookmark" class="entry-date"><abbr class="published"></abbr></a>' ,' from <a id="_twitter_client">web</a>' ,' </span>' ,' </td>' ,' <td width="10" align="right">' ,' <div class="status_actions" >' ,' <a href="#">' ,' <img border="0" title="Favorite this update" src="http://assets2.twitter.com/images/icon_star_empty.gif" id="status_star_809356512" alt="Icon_star_empty"/>' ,' </a>' ,' <a href="#">' ,' <img border="0" title="reply to Hedachi" src="http://assets1.twitter.com/images/reply.png" alt="reply to Hedachi"/>' ,' </a>' ,' </div>' ,' </td>' ,'</tr>' ].join('') ); $('#log').append(document.createTextNode('init:' +(Date.now() - initStarted))); $('#log').append('<br>'); // contextを作ってやる var record ={ "status_id": "status_820087354", "user_name": "monjudoh", "nick_name": "文殊堂", "profile_image": "http://s3.amazonaws.com/twitter_production/profile_images/51603464/purplenize_normal.png", "entry_content": [ {"type": "text", "text": "@"}, {"type": "reply", "user_name": "t_ishida"}, {"type": "text", "text": "一応、この間こんなの作った。"}, {"type": "link", "text": "http://d.hatena.ne.jp/monju...", "href": "http://d.hatena.ne.jp/monjudoh/20080526/1211797706"}, {"type": "text", "text": ""} ], "published": new Date("Mon May 26 2008 19:29:42 GMT+0900"), "twitter_client": false, "reply-url": false } var use_name = record['user_name']; var userUrl = 'http://twitter.com/' + record['user_name']; var nick_name = record['nick_name']; var status_id = record['status_id']; var entry_id = status_id.replace('status_',''); var entry_url = ['http://twitter.com/',use_name,'/statuses/',entry_id].join(''); var published = record['published']; var entry_content = record['entry_content']; var profile_image = record['profile_image']; var twitter_client = record['twitter_client']; var context = { '':function(elem){elem.attr('id',status_id);} ,'.url':function(elem){elem.attr('href',userUrl);} ,'.anchor':function(elem){elem.attr('name',status_id);} ,'.url>img':function(elem){elem.attr('src',profile_image).attr('alt',nick_name);} ,'.content>strong>a':function(elem){elem.attr('href',userUrl).attr('title',nick_name).text(use_name);} ,'.entry-date':function(elem){elem.attr('href',entry_url);} ,'.published':function(elem){ elem.text([published.getHours(),published.getMinutes(),published.getSeconds()].join(':')); } ,'.status_actions':function(elem){elem.attr('id','status_actions_'+entry_id);} ,'.entry-content':function(elem){ $.each(entry_content,function(i,value){ switch(value['type']){ case 'text': elem.append( document.createTextNode(value['text']) ); break; case 'reply': elem .append( $('<a/>').text(value['user_name']).attr('href','/'.concat(value['user_name'])) ) .append( document.createTextNode(' ') ); break; case 'link': elem .append( $('<a/>').text(value['href']).attr('href',value['href']) ) .append( document.createTextNode(' ') ); break; } }); } ,'#_twitter_client':function(elem){ if(twitter_client){ elem .attr('href',twitter_client.url) .removeAttr('id') .text(twitter_client.name); }else{ elem.replaceWith(elem.text()); } } }; // 表示確認 $('#timeline').append(entry.merge(context)); // 100回マージして時間を計る var mergeStarted = Date.now(); for(var i = 0;i < 100;i++){ entry.merge(context); } $('#log').append(document.createTextNode('merge*100:' +(Date.now() - mergeStarted))); }); --> </script> </head> <body> <div id="content"><table cellspacing="0" id="timeline" class="doing"></table></div> <div id="log"></div> </body> </html>
これを表示してみるとTwitterのエントリが1つ表示されます。
部分HTMLを渡して作ったテンプレートentryに、
entry.merge(context)で値を注入してエントリのDOMツリーを作っています。
インスタンス生成には16ms、merge100回には約3000msかかっています。
DOMツリー探索にかかる時間
var context = { '':function(elem){} ,'.url':function(elem){} ,'.anchor':function(elem){} ,'.url>img':function(elem){} ,'.content>strong>a':function(elem){} ,'.entry-date':function(elem){} ,'.published':function(elem){} ,'.status_actions':function(elem){} ,'.entry-content':function(elem){} ,'#_twitter_client':function(elem){} };
このようにしてDOM操作の部分をごそっと消してみましたが、
それでも、merge100回には1200ms程度はかかっているので、
改善の余地がありそうです。
続く