SlideShare ist ein Scribd-Unternehmen logo
1 von 84
Downloaden Sie, um offline zu lesen
12年5月20日星期日
一个前端 Javascript 模板引擎的实现与优化



                        流火 @ TaobaoUED
                        Blog: http://benben.cc




12年5月20日星期日
Juicer 的诞生




     1 循环     {@each}…{@/each}

     2 判断     {@if}…{@else if}…{@else}…{@/if}

     3 变量(支持自定义函数) ${varname|function}          support node.js only 5kb

     4 注释     {# comment here}

     5 辅助循环        {@each i in range(0,9)}




12年5月20日星期日
静态页面   含有丰富交互的应用      服务端
                 后端提供纯数据(接口化)
                  前端负责将数据生成页面




12年5月20日星期日
MVC 需要模板

     MVC最早是在SmallTalk语言的开发过程中总结出的一种设
     计模式,MVC分别代表了"模型"、"视图"和"控制",目的就
     是让不同的开发角色在大中型项目中各司其职。在网络应
     用程序的开发中,可以用下图来表示各概念之间的关系。




12年5月20日星期日
模板引擎的分类

     置换型模板引擎。


     置换就是将规定好的文本标记替换为目标内容。这种模板引擎实现简单,除了标签替换之外,很少
     支持诸如子模板引用、流程控制等。正如上面所说,我们几乎天天都在使用这种模板引擎。可以
     说,置换型模板引擎的思想是整个模板引擎界的基础。



     解释型模板引擎。


     解释型模板引擎的原理还是标记置换。只不过有了解释器的存在,可以支持更加复杂的标记和语
     法。



     编译型模板引擎。


     编译型模板引擎是相对于解释型模板引擎来说的,实际上定名为编译型模板引擎也不太合适,但我
     也没想到别的好名字,哈!




12年5月20日星期日
模板引擎基本原理

     模板引擎的基本机理就是替换(转换),将指定的标签转换为
     需要的业务数据;将指定的伪语句按照某种流程来变换输出。


     The gist of JavaScript templates is that you can take an HTML fragment interpolated
     with template variables and combine it with a JavaScript object, replacing those
     tem- plate variables with values from the object. Overall, JavaScript templating
     works in much the same way as templating libraries in other languages, such as
     PHP’s Smarty, Ruby’s ERB, and Python’s string formatting.

     - Javascript Web Application




12年5月20日星期日
JSON   Template




12年5月20日星期日
JSON   Template




12年5月20日星期日
Template
              JSON    Engine
                                Template




12年5月20日星期日
Template
              JSON    Engine
                                Template




12年5月20日星期日
Template
              JSON    Engine
                                Template




12年5月20日星期日
Template
              JSON    Engine
                                Template




                       HTML
                     Fragment




12年5月20日星期日
water     juicer     fruits



                      Template
              JSON     Engine
                                 Template




                        HTML
                      Fragment




12年5月20日星期日
拼字符串


      var json = { name: "liuhuo", blog: "ued.taobao.com"};



     var html = '<span class="name">' + json.name + ' (blog: ' + json.blog + ')</span>';



      <span class="name">流火 (blog: ued.taobao.com)</span>




12年5月20日星期日
拼字符串的进化




      var tpl = '<span class="name">{name} (blog: {blog})</span>';

      var html = sub(tpl, json);




12年5月20日星期日
拼字符串的进化



     function sub(str,data) {
         return str
             .replace(/{(.*?)}/igm,function($,$1) {
                 return data[$1]?data[$1]:$;
             });
     }




      var tpl = '<span class="name">{name} (blog: {blog})</span>';

      var html = sub(tpl, json);




12年5月20日星期日
YUI.Lang.sub




12年5月20日星期日
现实中的使用场景




12年5月20日星期日
12年5月20日星期日
doT     yayaTemplate
                   ejs
                            Mustache
                                             artTemplate
              nTenjin     handlebar
                                   Kissy template
                  micro template

                 ...
                              jQuery tmpl



12年5月20日星期日
12年5月20日星期日
is it nessary ? are u sure ?


              如无必要,勿增实体




12年5月20日星期日
12年5月20日星期日
Security




12年5月20日星期日
Security
               XSS escape




12年5月20日星期日
Security
                        XSS escape




              Syntax




12年5月20日星期日
Security
                                      XSS escape




               Syntax
              easy to write & read




12年5月20日星期日
Security
                                      XSS escape




               Syntax                              Performance
              easy to write & read




12年5月20日星期日
Security
                                      XSS escape




               Syntax                              Performance
              easy to write & read                 as faster as you can




12年5月20日星期日
Security
                                      XSS escape




               Syntax                              Performance
              easy to write & read                 as faster as you can




                               Error Handling




12年5月20日星期日
Security
                                      XSS escape




               Syntax                              Performance
              easy to write & read                 as faster as you can




                               Error Handling
                                      robustness




12年5月20日星期日
语法
                           * 资本主义的无限制进展,无疑的
     1. 纯粹派                要促进反资本主义,即共产主义。
     2. KISS派              —— 《人生十论》

     3. 中立派



    the templating syntax for most libraries is very similar, if not identical.

    - Javascript Web Application




    纯粹派(以ejs、nTenjin、doT为代表):
    追求纯粹,希望通过原生的 Javascript 语法来写模板,这类模板
    引擎的实现一定是编译型的,但是它们的写法往往让人抓狂。


    KISS派(以Mustache、Handlebar为代表):
    追求 KISS / Logic less, 这注定了这类模板引擎的实现是解释型
    的,也就注定了它们性能是有瓶颈的。



12年5月20日星期日
立场

     中立派,站在理性的角度重视性能


    浏览器对JavaScript有两个限制:调用栈大小限制和长时间运行
    脚本限制。不同浏览器对脚本运行时间的限制不一样。Firefox为
    10秒,Safari为5秒,Chrome没有单独的限制。一般情况下,
    JavaScript运行时间不要超过100ms,如果超过100ms,用户就
    会感觉失去了对界面的控制。




    100ms * 100w = 27.777hours




12年5月20日星期日
语法
  <ul>                                               <ul>                                            <ul>
      {{#list}}                                          {@each data.list as it,k}                       {{#each list as it,k}}
          {{#show}}                                          {@if it.show}                                   {{#if it.show}}
              <li>{{name}} (index: {{index}})</li>               <li>${it.name} (index: ${k})</li>               <li>{{it.name}} (index: {{k}})</li>
          {{/show}}                                          {@/if}                                          {{/if}}
      {{/list}}                                          {@/each}                                        {{/each}}
      {{#blah}}                                          {@each data.blah as it}                         {{#each blah as it}}
          <li>                                               <li>                                            <li>
              num: {{num}}                                       num: ${it.num}                                  num: {{it.num}}
              ...                                                {@if it.num==3}                                 {{#if it.num==3}}
              {{#inner}}                                             {@each it.inner as it2}                         {{#each it.inner as it2}}
                  <li>{{time}}</li>                                      <li>${it2.time}</li>                            <li>{{it2.time}}</li>
              {{/inner}}                                             {@/each}                                        {{/each}}
              ...                                                {@/if}                                          {{/if}}
          </li>                                              </li>                                           </li>
      {{/blah}}                                          {@/each}                                        {{/each}}
  </ul>                                              </ul>                                           </ul>

  <ul>                                                                      <ul>
      <% for(var i=0;i<list.length;i++) { %>                                    <?js for(var i=0;i<it.list.length;i++) { ?>
          <% if(list[i].show) { %>                                                  <?js if(it.list[i].show) { ?>
              <li><%= list[i].name %> (index: <%= i %>)</li>                            <li>${it.list[i].name} (index: ${i})</li>
          <% } %>                                                                   <?js } ?>
      <% } %>                                                                   <?js } ?>
      <% for(var i=0;i<blah.length;i++) { %>                                    <?js for(var i=0;i<it.blah.length;i++) { ?>
          <li>                                                                      <li>
              num: <%= blah[i].num %>                                                   num: ${it.blah[i].num}
              <% if(blah[i].num==3) { %>                                                <?js if(it.blah[i].num==3) { ?>           
                  <% for(var j=0;j<blah[i].inner.length;j++) { %>                           <?js for(var j=0;j<it.blah[i].inner.length;j++) { ?>
                      <li><%= blah[i].inner[j].time %></li>                                     <li>${it.blah[i].inner[j].time}</li>
                  <% } %>                                                                   <?js } ?>
              <% } %>                                                                   <?js } ?>
          </li>                                                                     </li>
      <% } %>                                                                   <?js } ?>
  </ul>                                                                     </ul>




12年5月20日星期日
JSON


     var data={
         list:[
             {name:'liuhuo',show:true},
             {name:'benben',show:false},
             {name:'taobao',show:true}
         ],
         blah:[
             {num:1},
             {num:2},
             {num:3,inner:[
                 {'time':'15:00'},
                 {'time':'16:00'},
                 {'time':'17:00'},
                 {'time':'18:00'}
             ]},
             {num:4}
         ]
     };




12年5月20日星期日
JSON                                  预期结果

     var data={                            <ul>
         list:[                                <li>liuhuo (index: 0)</li>
             {name:'liuhuo',show:true},        <li>benben (index: 1)</li>
             {name:'benben',show:false},       <li>taobao (index: 2)</li>
             {name:'taobao',show:true}         <li>num: 1</li>
         ],                                    <li>num: 2</li>
         blah:[                                <li>num: 3</li>
             {num:1},                          <li>15:00</li>
             {num:2},                          <li>16:00</li>
             {num:3,inner:[                    <li>17:00</li>
                 {'time':'15:00'},             <li>18:00</li>
                 {'time':'16:00'},             <li>num: 4</li>
                 {'time':'17:00'},         </ul>
                 {'time':'18:00'}
             ]},
             {num:4}
         ]
     };




12年5月20日星期日
12年5月20日星期日
<ul>
                  {@each data.list as it,k}
                      {@if it.show}
                          <li>${it.name} (index: ${k})</li>
                      {@/if}
                  {@/each}
                  {@each data.blah as it}
                      <li>

    juicer                num: ${it.num}
                          {@if it.num==3}
                              {@each it.inner as it2}
                                  <li>${it2.time}</li>
                              {@/each}
                          {@/if}
                      </li>
                  {@/each}
              </ul>




                         http://jsfiddle.net/paulguo/LpvwH/1/



12年5月20日星期日
<ul>
                  {{#each list as it,index}}
                      {{#if it.show}}
                          <li>{{it.name}} (index: {{index}})</li>
                      {{/if}}
                  {{/each}}
                  {{#each blah as it}}
                      <li>

     kissy                num: {{it.num}}
                          {{#if it.num==3}}
                              {{#each it.inner as it2}}
                                  <li>{{it2.time}}</li>
                              {{/each}}
                          {{/if}}
                      </li>
                  {{/each}}
              </ul>




                             http://jsfiddle.net/paulguo/yLg4Y/1/



12年5月20日星期日
<ul>
                  {{#each list as it,index}}
                      {{#if it.show}}
                          <li>{{it.name}} (index: {{index}})</li>
                      {{/if}}
                  {{/each}}
                  {{#each blah as it}}
                      <li>

     kissy                num: {{it.num}}
                          {{#if it.num==3}}
                              {{#each it.inner as it2}}
                                  <li>{{it2.time}}</li>
                              {{/each}}
                          {{/if}}
                      </li>
                  {{/each}}
              </ul>




                             http://jsfiddle.net/paulguo/yLg4Y/1/



12年5月20日星期日
<ul>
                  {{#list}}
                      {{#show}}
                          <li>{{name}} (index: {{index}})</li>
                      {{/show}}
                  {{/list}}
                  {{#blah}}

mustache              <li>
                          num: {{num}}
                          {{#inner}}
                              <li>{{time}}</li>
                          {{/inner}}
                      </li>
                  {{/blah}}
              </ul>




                         http://jsfiddle.net/paulguo/VCH9k/1/



12年5月20日星期日
<ul>
                  {{#list}}
                      {{#show}}
                          <li>{{name}} (index: {{index}})</li>
                      {{/show}}
                  {{/list}}
                  {{#blah}}

mustache              <li>
                          num: {{num}}
                          {{#inner}}
                              <li>{{time}}</li>
                          {{/inner}}
                      </li>
                  {{/blah}}
              </ul>




                         http://jsfiddle.net/paulguo/VCH9k/1/



12年5月20日星期日
<ul>
                  <% for(var i=0;i<list.length;i++) { %>
                      <% if(list[i].show) { %>
                          <li><%= list[i].name %> (index: <%= i %>)</li>
                      <% } %>
                  <% } %>
                  <% for(var i=0;i<blah.length;i++) { %>
                      <li>

    micro                 num: <%= blah[i].num %>
                          <% if(blah[i].num==3) { %>           
                              <% for(var j=0;j<blah[i].inner.length;j++) { %>
                                  <li><%= blah[i].inner[j].time %></li>
                              <% } %>
                          <% } %>
                      </li>
                  <% } %>
              </ul>




                                http://jsfiddle.net/paulguo/KsDhC/1/



12年5月20日星期日
<ul>
                  <% for(var i=0;i<list.length;i++) { %>
                      <% if(list[i].show) { %>
                          <li><%= list[i].name %> (index: <%= i %>)</li>
                      <% } %>
                  <% } %>
                  <% for(var i=0;i<blah.length;i++) { %>
                      <li>

    micro                 num: <%= blah[i].num %>
                          <% if(blah[i].num==3) { %>           
                              <% for(var j=0;j<blah[i].inner.length;j++) { %>
                                  <li><%= blah[i].inner[j].time %></li>
                              <% } %>
                          <% } %>
                      </li>
                  <% } %>
              </ul>




                                http://jsfiddle.net/paulguo/KsDhC/1/



12年5月20日星期日
<ul>
                  <?js for(var i=0;i<it.list.length;i++) { ?>
                      <?js if(it.list[i].show) { ?>
                          <li>${it.list[i].name} (index: ${i})</li>
                      <?js } ?>
                  <?js } ?>
                  <?js for(var i=0;i<it.blah.length;i++) { ?>
                      <li>

  nTenjin                 num: ${it.blah[i].num}
                          <?js if(it.blah[i].num==3) { ?>           
                              <?js for(var j=0;j<it.blah[i].inner.length;j++) { ?>
                                  <li>${it.blah[i].inner[j].time}</li>
                              <?js } ?>
                          <?js } ?>
                      </li>
                  <?js } ?>
              </ul>




                                  http://jsfiddle.net/paulguo/W7eVV/1/



12年5月20日星期日
<ul>
                  <?js for(var i=0;i<it.list.length;i++) { ?>
                      <?js if(it.list[i].show) { ?>
                          <li>${it.list[i].name} (index: ${i})</li>
                      <?js } ?>
                  <?js } ?>
                  <?js for(var i=0;i<it.blah.length;i++) { ?>
                      <li>

  nTenjin                 num: ${it.blah[i].num}
                          <?js if(it.blah[i].num==3) { ?>           
                              <?js for(var j=0;j<it.blah[i].inner.length;j++) { ?>
                                  <li>${it.blah[i].inner[j].time}</li>
                              <?js } ?>
                          <?js } ?>
                      </li>
                  <?js } ?>
              </ul>




                                  http://jsfiddle.net/paulguo/W7eVV/1/



12年5月20日星期日
性能 - jsperf




12年5月20日星期日
性能 - jsperf




                 http://jsperf.com/javascript-template-engine/15


12年5月20日星期日
性能 - 最大化渲染测试




12年5月20日星期日
性能 - 最大化渲染测试




12年5月20日星期日
性能 - 最大化渲染测试




12年5月20日星期日
Security
     var json={
     ! output:'<script>alert("XSS");</script>'
     };




12年5月20日星期日
Security
     var json={
     ! output:'<script>alert("XSS");</script>'
     };




     document.write




12年5月20日星期日
Security
     var json={
     ! output:'<script>alert("XSS");</script>'
     };




     document.write                        $(node).html()




12年5月20日星期日
Security
     var json={
     ! output:'<script>alert("XSS");</script>'
     };




     document.write                        $(node).html()

     juicer.to_html('${output}',json);
     //输出:&lt;script&gt;alert("XSS");&lt;/script&gt;

     juicer.to_html('$${output}',json);
     //输出:<script>alert("XSS");</script>




12年5月20日星期日
template




12年5月20日星期日
compile
       template             reusable function




12年5月20日星期日
compile
       template             reusable function
                                  compiled template




12年5月20日星期日
compile                             render
       template             reusable function                  html code
                                  compiled template




12年5月20日星期日
var json={
                  list:[
                      {name:"benben"},
                      {name:"liuhuo"}
                  ]
              };


              var tpl='{@each data.list as value, key} $${value.name} {@/each}';
              var compiled_tpl=juicer(tpl);




12年5月20日星期日
function anonymous(data) {
                  var data = data || {};
                  var out = '';
                  out += '';
                  for (var i0 = 0, l = data.list.length; i0 < l; i0++) {
                      var value = data.list[i0];
                      var key = i0;
                      out += '';
                      out += ((value.name));
                      out += '';
                  }
                  out += '';
                  return out;
              }




12年5月20日星期日
一些性能优化点




12年5月20日星期日
一些性能优化点




              using += instead of array.push




12年5月20日星期日
str += "one" + "two";


     When evaluating this code, four steps are taken:


     1. A temporary string is created in memory.
     2. The concatenated value "onetwo" is assigned to the temporary string.
     3. The temporary string is concatenated with the current value of str.
     4. The result is assigned to str.

     - Hign Performance Javascript




12年5月20日星期日
str = ["one", "two"].join(‘’);




     This dramatic improvement results from avoiding repeatedly allocating memory for
     and copying progressively larger and larger strings. When joining an array, the
     browser allocates enough memory to hold the complete string, and never copies the
     same part of the final string more than once.

     - Hign Performance Javascript




12年5月20日星期日
12年5月20日星期日
Browser string optimizations have changed the string concatenation picture.

              Firefox was the first browser to optimize string concatenation. Beginning with version 1.0,
              the array technique is actually slower than using the plus operator in all cases. Other
              browsers have also optimized string concatenation, so Safari, Opera, Chrome, and
              Internet Explorer 8 also show better performance using the plus operator. Internet
              Explorer prior to version 8 didn’t have such an optimization, and so the array technique is
              always faster than the plus operator.



              — Writing Efficient JavaScript: Chapter 7 – Even Faster Websites




12年5月20日星期日
The V8 engine (used in Google Chrome) uses this code to do string concatenation:




              // ECMA-262, section 15.5.4.6
              function StringConcat() {
                if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
                  throw MakeTypeError("called_on_null_or_undefined", ["String.prototype.concat"]);
                }
                var len = %_ArgumentsLength();
                var this_as_string = TO_STRING_INLINE(this);
                if (len === 1) {
                  return this_as_string + %_Arguments(0);
                }
                var parts = new InternalArray(len + 1);
                parts[0] = this_as_string;
                for (var i = 0; i < len; i++) {
                  var part = %_Arguments(i);
                  parts[i + 1] = TO_STRING_INLINE(part);
                }
                return %StringBuilderConcat(parts, len + 1, "");
              }




12年5月20日星期日
一些性能优化点




              avoid using with block




12年5月20日星期日
12年5月20日星期日
var person = {                        The with construct introduces an extra scope for
             name: "Nicholas",                 the script engine to search through whenever a
             age: 30                           variable is referenced. This alone produces a
         };                                    minor performance decrease. However, the
                                               contents of that scope are not known at compile
         function displayInfo(){               time, meaning that the compiler cannot optimize
             var count = 5;                    for it, in the same way as it can with normal scopes
             with(person){                     (such as those created by functions).
                 alert(name + " is " + age);
                 alert("Count is " + count);
             }
         }

         displayInfo();




12年5月20日星期日
一些性能优化点




              cache the compiled template.




12年5月20日星期日
Cache The Compiled Template



     JavaScript, like many scripting languages, allows you to take a string containing
     code and execute it from within running code. There are four standard ways to
     accomplish this: eval(), the Function() constructor, setTimeout(), and setInterval().
     Each of these functions allows you to pass in a string of JavaScript code and have it
     executed.

     - Hign Performance Javascript




12年5月20日星期日
Juicer 的使用方法.




12年5月20日星期日
12年5月20日星期日
12年5月20日星期日
12年5月20日星期日
{@each list as it, k}
                  <span class=”{@if k+2>list.length}notdot{@/if}”>...</span>
              {@/each}




12年5月20日星期日
http://taobao.com/s?q=%E6%B7%98%E5%AE%9D




              json={query:’淘宝’,...}
              http://taobao.com/s?q=${query|encodeURIComponent}




12年5月20日星期日
12年5月20日星期日
12年5月20日星期日
12年5月20日星期日
Q&A

              juicer(‘${over}’, {over:‘thanks!’});




12年5月20日星期日

Weitere ähnliche Inhalte

Ähnlich wie 一个前端Js模板引擎的实现和优化

AngularJS Sharing
AngularJS SharingAngularJS Sharing
AngularJS SharingTom Chen
 
iOS开发常用库推荐之一@techparty
iOS开发常用库推荐之一@techpartyiOS开发常用库推荐之一@techparty
iOS开发常用库推荐之一@techpartyGump Law
 
May the source_be_with_you
May the source_be_with_youMay the source_be_with_you
May the source_be_with_youEddie Kao
 
jQuery底层架构
jQuery底层架构jQuery底层架构
jQuery底层架构fangdeng
 
Elasticsearch 實戰介紹
Elasticsearch 實戰介紹Elasticsearch 實戰介紹
Elasticsearch 實戰介紹Kang-min Liu
 

Ähnlich wie 一个前端Js模板引擎的实现和优化 (6)

AngularJS Sharing
AngularJS SharingAngularJS Sharing
AngularJS Sharing
 
iOS开发常用库推荐之一@techparty
iOS开发常用库推荐之一@techpartyiOS开发常用库推荐之一@techparty
iOS开发常用库推荐之一@techparty
 
May the source_be_with_you
May the source_be_with_youMay the source_be_with_you
May the source_be_with_you
 
Xml基础培训
Xml基础培训Xml基础培训
Xml基础培训
 
jQuery底层架构
jQuery底层架构jQuery底层架构
jQuery底层架构
 
Elasticsearch 實戰介紹
Elasticsearch 實戰介紹Elasticsearch 實戰介紹
Elasticsearch 實戰介紹
 

一个前端Js模板引擎的实现和优化

  • 2. 一个前端 Javascript 模板引擎的实现与优化 流火 @ TaobaoUED Blog: http://benben.cc 12年5月20日星期日
  • 3. Juicer 的诞生 1 循环 {@each}…{@/each} 2 判断 {@if}…{@else if}…{@else}…{@/if} 3 变量(支持自定义函数) ${varname|function} support node.js only 5kb 4 注释 {# comment here} 5 辅助循环 {@each i in range(0,9)} 12年5月20日星期日
  • 4. 静态页面 含有丰富交互的应用 服务端 后端提供纯数据(接口化) 前端负责将数据生成页面 12年5月20日星期日
  • 5. MVC 需要模板 MVC最早是在SmallTalk语言的开发过程中总结出的一种设 计模式,MVC分别代表了"模型"、"视图"和"控制",目的就 是让不同的开发角色在大中型项目中各司其职。在网络应 用程序的开发中,可以用下图来表示各概念之间的关系。 12年5月20日星期日
  • 6. 模板引擎的分类 置换型模板引擎。 置换就是将规定好的文本标记替换为目标内容。这种模板引擎实现简单,除了标签替换之外,很少 支持诸如子模板引用、流程控制等。正如上面所说,我们几乎天天都在使用这种模板引擎。可以 说,置换型模板引擎的思想是整个模板引擎界的基础。 解释型模板引擎。 解释型模板引擎的原理还是标记置换。只不过有了解释器的存在,可以支持更加复杂的标记和语 法。 编译型模板引擎。 编译型模板引擎是相对于解释型模板引擎来说的,实际上定名为编译型模板引擎也不太合适,但我 也没想到别的好名字,哈! 12年5月20日星期日
  • 7. 模板引擎基本原理 模板引擎的基本机理就是替换(转换),将指定的标签转换为 需要的业务数据;将指定的伪语句按照某种流程来变换输出。 The gist of JavaScript templates is that you can take an HTML fragment interpolated with template variables and combine it with a JavaScript object, replacing those tem- plate variables with values from the object. Overall, JavaScript templating works in much the same way as templating libraries in other languages, such as PHP’s Smarty, Ruby’s ERB, and Python’s string formatting. - Javascript Web Application 12年5月20日星期日
  • 8. JSON Template 12年5月20日星期日
  • 9. JSON Template 12年5月20日星期日
  • 10. Template JSON Engine Template 12年5月20日星期日
  • 11. Template JSON Engine Template 12年5月20日星期日
  • 12. Template JSON Engine Template 12年5月20日星期日
  • 13. Template JSON Engine Template HTML Fragment 12年5月20日星期日
  • 14. water juicer fruits Template JSON Engine Template HTML Fragment 12年5月20日星期日
  • 15. 拼字符串 var json = { name: "liuhuo", blog: "ued.taobao.com"}; var html = '<span class="name">' + json.name + ' (blog: ' + json.blog + ')</span>'; <span class="name">流火 (blog: ued.taobao.com)</span> 12年5月20日星期日
  • 16. 拼字符串的进化 var tpl = '<span class="name">{name} (blog: {blog})</span>'; var html = sub(tpl, json); 12年5月20日星期日
  • 17. 拼字符串的进化 function sub(str,data) { return str .replace(/{(.*?)}/igm,function($,$1) { return data[$1]?data[$1]:$; }); } var tpl = '<span class="name">{name} (blog: {blog})</span>'; var html = sub(tpl, json); 12年5月20日星期日
  • 21. doT yayaTemplate ejs Mustache artTemplate nTenjin handlebar Kissy template micro template ... jQuery tmpl 12年5月20日星期日
  • 23. is it nessary ? are u sure ? 如无必要,勿增实体 12年5月20日星期日
  • 26. Security XSS escape 12年5月20日星期日
  • 27. Security XSS escape Syntax 12年5月20日星期日
  • 28. Security XSS escape Syntax easy to write & read 12年5月20日星期日
  • 29. Security XSS escape Syntax Performance easy to write & read 12年5月20日星期日
  • 30. Security XSS escape Syntax Performance easy to write & read as faster as you can 12年5月20日星期日
  • 31. Security XSS escape Syntax Performance easy to write & read as faster as you can Error Handling 12年5月20日星期日
  • 32. Security XSS escape Syntax Performance easy to write & read as faster as you can Error Handling robustness 12年5月20日星期日
  • 33. 语法 * 资本主义的无限制进展,无疑的 1. 纯粹派 要促进反资本主义,即共产主义。 2. KISS派 —— 《人生十论》 3. 中立派 the templating syntax for most libraries is very similar, if not identical. - Javascript Web Application 纯粹派(以ejs、nTenjin、doT为代表): 追求纯粹,希望通过原生的 Javascript 语法来写模板,这类模板 引擎的实现一定是编译型的,但是它们的写法往往让人抓狂。 KISS派(以Mustache、Handlebar为代表): 追求 KISS / Logic less, 这注定了这类模板引擎的实现是解释型 的,也就注定了它们性能是有瓶颈的。 12年5月20日星期日
  • 34. 立场 中立派,站在理性的角度重视性能 浏览器对JavaScript有两个限制:调用栈大小限制和长时间运行 脚本限制。不同浏览器对脚本运行时间的限制不一样。Firefox为 10秒,Safari为5秒,Chrome没有单独的限制。一般情况下, JavaScript运行时间不要超过100ms,如果超过100ms,用户就 会感觉失去了对界面的控制。 100ms * 100w = 27.777hours 12年5月20日星期日
  • 35. 语法 <ul> <ul> <ul>     {{#list}}     {@each data.list as it,k}     {{#each list as it,k}}         {{#show}}         {@if it.show}         {{#if it.show}}             <li>{{name}} (index: {{index}})</li>             <li>${it.name} (index: ${k})</li>             <li>{{it.name}} (index: {{k}})</li>         {{/show}}         {@/if}         {{/if}}     {{/list}}     {@/each}     {{/each}}     {{#blah}}     {@each data.blah as it}     {{#each blah as it}}         <li>         <li>         <li>             num: {{num}}             num: ${it.num}             num: {{it.num}}             ...             {@if it.num==3}             {{#if it.num==3}}             {{#inner}}                 {@each it.inner as it2}                 {{#each it.inner as it2}}                 <li>{{time}}</li>                     <li>${it2.time}</li>                     <li>{{it2.time}}</li>             {{/inner}}                 {@/each}                 {{/each}}             ...             {@/if}             {{/if}}         </li>         </li>         </li>     {{/blah}}     {@/each}     {{/each}} </ul> </ul> </ul> <ul> <ul>     <% for(var i=0;i<list.length;i++) { %>     <?js for(var i=0;i<it.list.length;i++) { ?>         <% if(list[i].show) { %>         <?js if(it.list[i].show) { ?>             <li><%= list[i].name %> (index: <%= i %>)</li>             <li>${it.list[i].name} (index: ${i})</li>         <% } %>         <?js } ?>     <% } %>     <?js } ?>     <% for(var i=0;i<blah.length;i++) { %>     <?js for(var i=0;i<it.blah.length;i++) { ?>         <li>         <li>             num: <%= blah[i].num %>             num: ${it.blah[i].num}             <% if(blah[i].num==3) { %>                        <?js if(it.blah[i].num==3) { ?>                            <% for(var j=0;j<blah[i].inner.length;j++) { %>                 <?js for(var j=0;j<it.blah[i].inner.length;j++) { ?>                     <li><%= blah[i].inner[j].time %></li>                     <li>${it.blah[i].inner[j].time}</li>                 <% } %>                 <?js } ?>             <% } %>             <?js } ?>         </li>         </li>     <% } %>     <?js } ?> </ul> </ul> 12年5月20日星期日
  • 36. JSON var data={     list:[         {name:'liuhuo',show:true},         {name:'benben',show:false},         {name:'taobao',show:true}     ],     blah:[         {num:1},         {num:2},         {num:3,inner:[             {'time':'15:00'},             {'time':'16:00'},             {'time':'17:00'},             {'time':'18:00'}         ]},         {num:4}     ] }; 12年5月20日星期日
  • 37. JSON 预期结果 var data={ <ul>     list:[     <li>liuhuo (index: 0)</li>         {name:'liuhuo',show:true},     <li>benben (index: 1)</li>         {name:'benben',show:false},     <li>taobao (index: 2)</li>         {name:'taobao',show:true}     <li>num: 1</li>     ],     <li>num: 2</li>     blah:[     <li>num: 3</li>         {num:1},     <li>15:00</li>         {num:2},     <li>16:00</li>         {num:3,inner:[     <li>17:00</li>             {'time':'15:00'},     <li>18:00</li>             {'time':'16:00'},     <li>num: 4</li>             {'time':'17:00'}, </ul>             {'time':'18:00'}         ]},         {num:4}     ] }; 12年5月20日星期日
  • 39. <ul>     {@each data.list as it,k}         {@if it.show}             <li>${it.name} (index: ${k})</li>         {@/if}     {@/each}     {@each data.blah as it}         <li> juicer             num: ${it.num}             {@if it.num==3}                 {@each it.inner as it2}                     <li>${it2.time}</li>                 {@/each}             {@/if}         </li>     {@/each} </ul> http://jsfiddle.net/paulguo/LpvwH/1/ 12年5月20日星期日
  • 40. <ul>     {{#each list as it,index}}         {{#if it.show}}             <li>{{it.name}} (index: {{index}})</li>         {{/if}}     {{/each}}     {{#each blah as it}}         <li> kissy             num: {{it.num}}             {{#if it.num==3}}                 {{#each it.inner as it2}}                     <li>{{it2.time}}</li>                 {{/each}}             {{/if}}         </li>     {{/each}} </ul> http://jsfiddle.net/paulguo/yLg4Y/1/ 12年5月20日星期日
  • 41. <ul>     {{#each list as it,index}}         {{#if it.show}}             <li>{{it.name}} (index: {{index}})</li>         {{/if}}     {{/each}}     {{#each blah as it}}         <li> kissy             num: {{it.num}}             {{#if it.num==3}}                 {{#each it.inner as it2}}                     <li>{{it2.time}}</li>                 {{/each}}             {{/if}}         </li>     {{/each}} </ul> http://jsfiddle.net/paulguo/yLg4Y/1/ 12年5月20日星期日
  • 42. <ul>     {{#list}}         {{#show}}             <li>{{name}} (index: {{index}})</li>         {{/show}}     {{/list}}     {{#blah}} mustache         <li>             num: {{num}}             {{#inner}}                 <li>{{time}}</li>             {{/inner}}         </li>     {{/blah}} </ul> http://jsfiddle.net/paulguo/VCH9k/1/ 12年5月20日星期日
  • 43. <ul>     {{#list}}         {{#show}}             <li>{{name}} (index: {{index}})</li>         {{/show}}     {{/list}}     {{#blah}} mustache         <li>             num: {{num}}             {{#inner}}                 <li>{{time}}</li>             {{/inner}}         </li>     {{/blah}} </ul> http://jsfiddle.net/paulguo/VCH9k/1/ 12年5月20日星期日
  • 44. <ul>     <% for(var i=0;i<list.length;i++) { %>         <% if(list[i].show) { %>             <li><%= list[i].name %> (index: <%= i %>)</li>         <% } %>     <% } %>     <% for(var i=0;i<blah.length;i++) { %>         <li> micro             num: <%= blah[i].num %>             <% if(blah[i].num==3) { %>                            <% for(var j=0;j<blah[i].inner.length;j++) { %>                     <li><%= blah[i].inner[j].time %></li>                 <% } %>             <% } %>         </li>     <% } %> </ul> http://jsfiddle.net/paulguo/KsDhC/1/ 12年5月20日星期日
  • 45. <ul>     <% for(var i=0;i<list.length;i++) { %>         <% if(list[i].show) { %>             <li><%= list[i].name %> (index: <%= i %>)</li>         <% } %>     <% } %>     <% for(var i=0;i<blah.length;i++) { %>         <li> micro             num: <%= blah[i].num %>             <% if(blah[i].num==3) { %>                            <% for(var j=0;j<blah[i].inner.length;j++) { %>                     <li><%= blah[i].inner[j].time %></li>                 <% } %>             <% } %>         </li>     <% } %> </ul> http://jsfiddle.net/paulguo/KsDhC/1/ 12年5月20日星期日
  • 46. <ul>     <?js for(var i=0;i<it.list.length;i++) { ?>         <?js if(it.list[i].show) { ?>             <li>${it.list[i].name} (index: ${i})</li>         <?js } ?>     <?js } ?>     <?js for(var i=0;i<it.blah.length;i++) { ?>         <li> nTenjin             num: ${it.blah[i].num}             <?js if(it.blah[i].num==3) { ?>                            <?js for(var j=0;j<it.blah[i].inner.length;j++) { ?>                     <li>${it.blah[i].inner[j].time}</li>                 <?js } ?>             <?js } ?>         </li>     <?js } ?> </ul> http://jsfiddle.net/paulguo/W7eVV/1/ 12年5月20日星期日
  • 47. <ul>     <?js for(var i=0;i<it.list.length;i++) { ?>         <?js if(it.list[i].show) { ?>             <li>${it.list[i].name} (index: ${i})</li>         <?js } ?>     <?js } ?>     <?js for(var i=0;i<it.blah.length;i++) { ?>         <li> nTenjin             num: ${it.blah[i].num}             <?js if(it.blah[i].num==3) { ?>                            <?js for(var j=0;j<it.blah[i].inner.length;j++) { ?>                     <li>${it.blah[i].inner[j].time}</li>                 <?js } ?>             <?js } ?>         </li>     <?js } ?> </ul> http://jsfiddle.net/paulguo/W7eVV/1/ 12年5月20日星期日
  • 49. 性能 - jsperf http://jsperf.com/javascript-template-engine/15 12年5月20日星期日
  • 53. Security var json={ ! output:'<script>alert("XSS");</script>' }; 12年5月20日星期日
  • 54. Security var json={ ! output:'<script>alert("XSS");</script>' }; document.write 12年5月20日星期日
  • 55. Security var json={ ! output:'<script>alert("XSS");</script>' }; document.write $(node).html() 12年5月20日星期日
  • 56. Security var json={ ! output:'<script>alert("XSS");</script>' }; document.write $(node).html() juicer.to_html('${output}',json); //输出:&lt;script&gt;alert("XSS");&lt;/script&gt; juicer.to_html('$${output}',json); //输出:<script>alert("XSS");</script> 12年5月20日星期日
  • 58. compile template reusable function 12年5月20日星期日
  • 59. compile template reusable function compiled template 12年5月20日星期日
  • 60. compile render template reusable function html code compiled template 12年5月20日星期日
  • 61. var json={     list:[         {name:"benben"},         {name:"liuhuo"}     ] }; var tpl='{@each data.list as value, key} $${value.name} {@/each}'; var compiled_tpl=juicer(tpl); 12年5月20日星期日
  • 62. function anonymous(data) {     var data = data || {};     var out = '';     out += '';     for (var i0 = 0, l = data.list.length; i0 < l; i0++) {         var value = data.list[i0];         var key = i0;         out += '';         out += ((value.name));         out += '';     }     out += '';     return out; } 12年5月20日星期日
  • 64. 一些性能优化点 using += instead of array.push 12年5月20日星期日
  • 65. str += "one" + "two"; When evaluating this code, four steps are taken: 1. A temporary string is created in memory. 2. The concatenated value "onetwo" is assigned to the temporary string. 3. The temporary string is concatenated with the current value of str. 4. The result is assigned to str. - Hign Performance Javascript 12年5月20日星期日
  • 66. str = ["one", "two"].join(‘’); This dramatic improvement results from avoiding repeatedly allocating memory for and copying progressively larger and larger strings. When joining an array, the browser allocates enough memory to hold the complete string, and never copies the same part of the final string more than once. - Hign Performance Javascript 12年5月20日星期日
  • 68. Browser string optimizations have changed the string concatenation picture. Firefox was the first browser to optimize string concatenation. Beginning with version 1.0, the array technique is actually slower than using the plus operator in all cases. Other browsers have also optimized string concatenation, so Safari, Opera, Chrome, and Internet Explorer 8 also show better performance using the plus operator. Internet Explorer prior to version 8 didn’t have such an optimization, and so the array technique is always faster than the plus operator. — Writing Efficient JavaScript: Chapter 7 – Even Faster Websites 12年5月20日星期日
  • 69. The V8 engine (used in Google Chrome) uses this code to do string concatenation: // ECMA-262, section 15.5.4.6 function StringConcat() {   if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {     throw MakeTypeError("called_on_null_or_undefined", ["String.prototype.concat"]);   }   var len = %_ArgumentsLength();   var this_as_string = TO_STRING_INLINE(this);   if (len === 1) {     return this_as_string + %_Arguments(0);   }   var parts = new InternalArray(len + 1);   parts[0] = this_as_string;   for (var i = 0; i < len; i++) {     var part = %_Arguments(i);     parts[i + 1] = TO_STRING_INLINE(part);   }   return %StringBuilderConcat(parts, len + 1, ""); } 12年5月20日星期日
  • 70. 一些性能优化点 avoid using with block 12年5月20日星期日
  • 72. var person = { The with construct introduces an extra scope for name: "Nicholas", the script engine to search through whenever a age: 30 variable is referenced. This alone produces a }; minor performance decrease. However, the contents of that scope are not known at compile function displayInfo(){ time, meaning that the compiler cannot optimize var count = 5; for it, in the same way as it can with normal scopes with(person){ (such as those created by functions). alert(name + " is " + age); alert("Count is " + count); } } displayInfo(); 12年5月20日星期日
  • 73. 一些性能优化点 cache the compiled template. 12年5月20日星期日
  • 74. Cache The Compiled Template JavaScript, like many scripting languages, allows you to take a string containing code and execute it from within running code. There are four standard ways to accomplish this: eval(), the Function() constructor, setTimeout(), and setInterval(). Each of these functions allows you to pass in a string of JavaScript code and have it executed. - Hign Performance Javascript 12年5月20日星期日
  • 79. {@each list as it, k} <span class=”{@if k+2>list.length}notdot{@/if}”>...</span> {@/each} 12年5月20日星期日
  • 80. http://taobao.com/s?q=%E6%B7%98%E5%AE%9D json={query:’淘宝’,...} http://taobao.com/s?q=${query|encodeURIComponent} 12年5月20日星期日
  • 84. Q&A juicer(‘${over}’, {over:‘thanks!’}); 12年5月20日星期日