jqMobiはjQueryからどうやって
  軽量化しているかの一側面




               有路 央
              伊達巻の日。
jQueryとjqMobiを単純比較してみる
• jQuery minified 92kb
• jqMobi min 15kb

• jQueryMobile minified 89kb
• jqUi min 71kb
全て圧縮/難読化済みのjsのプログラムサイズ
ところで

 みなさん、jQueryにおけるselector使ってますか?


 •   $(“#id”)
 •   $(“.class”)
 •   $(“div.music > spant.title”)
 •   $(“div.class, span.class”)

              などなど
ところで

 みなさん、jQueryにおけるselector使ってますか?


 •   $(“#id”)
 •   $(“.class”)
 •   $(“div.music > spant.title”)
 •   $(“div.class, span.class”)

              などなど

     これらがどうやって動いているか見てみましょ
     う
http://code.jquery.com/jquery-1.7.2.js
        init: function( selector, context, rootjQuery ) {
          var match, elem, ret, doc;

         // Handle $(""), $(null), or $(undefined)     $() <- jQuery Objectが
         if ( !selector ) {
                                                       欲しいときなど
           return this;
         }

         // Handle $(DOMElement)
         if ( selector.nodeType ) {
           this.context = this[0] = selector;
                                                        $(document)
           this.length = 1;                             $(document.getElementById(“id”)) な
           return this;                                 ど
         }

         // The body element only exists once, optimize finding it
         if ( selector === "body" && !context && document.body ) {
           this.context = document;
           this[0] = document.body;
           this.selector = selector;              $(“body”)用
           this.length = 1;
           return this;
         }
ここからが本番

 事前準備
// Handle HTML strings
  if ( typeof selector === "string" ) {
    // Are we dealing with HTML string or an ID?
    if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
      // Assume that strings that start and end with <> are HTML and skip the regex check
      match = [ null, selector, null ];
                                                 Htmlタグを入力したとき
  } else {
    match = quickExpr.exec( selector );
  }
                 quickExpr = /^(?:[^#<]*(<[wW]+>)[^>]*$|#([w-]*)$)/

                             タグ(<>で囲まれたワード)と#で始まる文
                             字を抜き出している

                               match[0] = selectorの該当全部
                               match[1] = タグの中身(があった場合)
                               match[2] = #から始まるワード(があった場
                               合)
タグの場合
  // Verify a match, and that no context was specified for #id
     if ( match && (match[1] || !context) ) {

     // HANDLE: $(html) -> $(array)
     if ( match[1] ) {
       context = context instanceof jQuery ? context[0] : context;
       doc = ( context ? context.ownerDocument || context : document );

       // If a single string is passed in and it's a single tag
       // just do a createElement and skip the rest
       ret = rsingleTag.exec( selector );
                                                                         Htmlタグからelementを作る
       if ( ret ) {
         if ( jQuery.isPlainObject( context ) ) {
           selector = [ document.createElement( ret[1] ) ];
           jQuery.fn.attr.call( selector, context, true );

        } else {
          selector = [ doc.createElement( ret[1] ) ];
        }

       } else {
         ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
         selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;
       }

       return jQuery.merge( this, selector );
$(“#id”)の場合
      // HANDLE: $("#id")
          } else {
            elem = document.getElementById( match[2] );

             // Check parentNode to catch when Blackberry 4.6 returns
             // nodes that are no longer in the document #6963
             if ( elem && elem.parentNode ) {
               // Handle the case where IE and Opera return items
               // by name instead of ID
               if ( elem.id !== match[2] ) {                   IDからgetElementByIdで
                 return rootjQuery.find( selector );           Elementを取得
               }

                 // Otherwise, we inject the element directly into the jQuery object
                 this.length = 1;
                 this[0] = elem;
             }

             this.context = document;
             this.selector = selector;
             return this;
         }
ここまでselectorは#idのみ。
では .class や より複雑なCSS selectorはどうやって判定しているのか

  // HANDLE: $(expr, $(...))
     } else if ( !context || context.jquery ) {
       return ( context || rootjQuery ).find( selector );

     // HANDLE: $(expr, context)                            jQuery.find()を利用
     // (which is just equivalent to: $(context).find(expr)
     } else {
       return this.constructor( context ).find( selector );
     }



            では findを見てみましょう
jQuery Line:5384
     Sizzle.attr = jQuery.attr;
     Sizzle.selectors.attrMap = {};
     jQuery.find = Sizzle;
     jQuery.expr = Sizzle.selectors;
     jQuery.expr[":"] = jQuery.expr.filters;
     jQuery.unique = Sizzle.uniqueSort;
     jQuery.text = Sizzle.getText;
     jQuery.isXMLDoc = Sizzle.isXML;
     jQuery.contains = Sizzle.contains;


                   Sizzle   だそうです。
                             Sizzleってなに?
Sizzleとは   http://sizzlejs.com/

 2008/11/13に書かれたとあるblogの中にあったので引用
   http://webos-goodies.jp/archives/51408207.html
              jQuery の開発者である John Resig 氏が、
              次期 jQuery のために開発しているセレクタエンジンです。


    これがjQueryに導入されリリースされたのが2009/1にでたjQuery1.3です。


       jQueryのソースにもこんな感じで書いてあります
           /*!
            * Sizzle CSS Selector Engine
            * Copyright 2011, The Dojo Foundation
            * Released under the MIT, BSD, and GPL Licenses.
            * More information: http://sizzlejs.com/
            */
Sizzleだけで、34kb 1,442行のjsプログラムです(無圧縮時)
jQuery.min.js上の圧縮/難読化済みでも約11kb (有路調べ)

内部的にも正規表現を多用しており決して速いとはいえないプログラムになっていま
Sizzleだけで、34kb 1,442行のjsプログラムです(無圧縮時)
jQuery.min.js上の圧縮/難読化済みでも約11kb (有路調べ)

内部的にも正規表現を多用しており決して速いとはいえないプログラムになっていま



                    しかも
たいていのブラウザのjavascriptエンジン内には
querySelectorAllというselectorを実装しているのです。
ブラウザ側で実行するので当然高速です
たいていのブラウザのjavascriptエンジン内には
querySelectorAllというselectorを実装しているのです。
ブラウザ側で実行するので当然高速です


                              つまりはSizzleはいらない子
たいていのブラウザのjavascriptエンジン内には
querySelectorAllというselectorを実装しているのです。
ブラウザ側で実行するので当然高速です


                                             つまりはSizzleはいらない子
 jQuery内でも

     ~(Sizzleのコード) ~

     if ( document.querySelectorAll ) {
      ~(中略)~
         Sizzle = function( query, context, extra, seed ) {
            context = context || document;
      ~(中略)~
               return makeArray( context.querySelectorAll(query), extra );
      ~(後略)~
                                                と容赦なく上書きしてます
jQueryからもSizzleのコードを削除したいのですが、
   レガシーなブラウザのために残してあるのが実際のところでしょう

            Androidのwebブラウザ・iPhoneのブラウザ等にも
            当然querySelectorAll は実装されています。



https://developer.mozilla.org/en/DOM/Document.querySelectorAll
                           Firefox       Internet                Safari
Feature      Chrome                                   Opera
                           (Gecko)       Explorer                (WebKit)
Basic support 1            3.5 (1.9.1)   8            10         3.2 (525.3)

                           Firefox
                                                      Opera
Feature       Android      Mobile        IE Mobile               Safari Mobile
                                                      Mobile
                           (Gecko)
Basic support 2.1          yes           9            10.0       3.2
このことからjqMobiでは
   function _selector(selector, what) {
    var dom;
     if (selector[0] === "#" && selector.indexOf(" ") === -1 && selector.indexOf(">") === -1) {
      if (what == document)
      dom = what.getElementById(selector.replace("#", ""));
      else
      dom = [].slice.call(what.querySelectorAll(selector));
      return dom;
     }
     selector=selector.trim();
     if (selector[0] === "<" && selector[selector.length - 1] === ">") //html
     {
      var tmp = document.createElement("div");
      tmp.innerHTML = selector.trim();
      dom = [].slice.call(tmp.childNodes);
     } else {
      dom = [].slice.call(what.querySelectorAll(selector));
     }
    return dom;
    }



                    約20行程度:700byte弱(無圧縮時)にすることに成功しています
まと
め
• jQueryは過去のしがらみから重い(部分がある)
• jqMobiは「mobileに特化」しているおかげで
  切り捨てられるコードがある




           以上。ご静聴ありがとうございました

J qmobiはjqueryから軽量化しているか