• 締切済み

このコードを処理速度向上させることはできますか?

このコードを処理速度向上させることはできますか? <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script type="text/javascript"> //<![CDATA[ function className(str){ var alltag = document.getElementsByTagName("*"); var ary = []; for(var i=0;i<alltag.length;i++){ if("."+alltag[i].className == str){ ary.push(alltag[i]); } } return ary; } window.$ = function(str){ var ID = str.match(/^#(\w+)/), CLASS = str.match(/^\.(\w+)/), TAG = str.match(/^(\w+)|(\*)/), node = str.match(/^doc/)? document: TAG? document.getElementsByTagName(RegExp.$1==""?RegExp.$2:RegExp.$1): ID? document.getElementById(RegExp.$1): CLASS? navigator.appVersion.toLowerCase().indexOf("msie")? className(str): document.getElementsByClassName(RegExp.$1): null; this.style = function(css){ css = css.split(/\:|\;/); if(ID){ for(var j=0;j<css.length;j++) node.style[css[j].replace(/\s+/g,"").replace(/\-(\w)/,function($1){$1=$1.substr(1);return $1.toUpperCase()})] = css[j+1]; }else{ for(var i=0;i<node.length;i++){ for(var j=0;j<css.length;j++) node[i].style[css[j].replace(/\s+/g,"").replace(/\-(\w)/,function($1){$1=$1.substr(1);return $1.toUpperCase()})] = css[j+1]; } } } return this; } window.onload = function(){ var st = new Date().getTime(); for(var i=0;i<10000;i++){ $('#wrap').style("color:#00f; background:#f00; border-left:10px solid #000;"); $('div').style("border-right:10px solid #000; width:100px; height:100px; margin:10px;"); $('.cl').style("border-top:10px solid #000; background:#00f;"); } var end = new Date().getTime(); alert(end-st); } //]]> </script> <title></title> </head> <body> <div id="wrap">aaaaa</div> <div class="cl">bbb</div> <div class="cl">ccc</div> </body> </html> 他にも、もっとこうしたほうが…等ありましたら教えてください。どうか宜しくお願いします。

みんなの回答

回答No.12

えぇ~~ その stock ! ベンチマークぶっ壊しの「落ち」だったのに!

  • 15mm
  • ベストアンサー率65% (65/100)
回答No.11

ブラウザの再描画を減らそう、ということで、<style>の中を弄って一括で。 望む動作と違うかもしれませんし、 ブラウザごとの仕様の違いへの対応とかがまだ途中ですが、参考までにどうぞ。 (ところでちゃんと速くなってるのか? 短くはなってるけど) babu_babooさんのstockのアイデア頂きました。 var $=(function(){  var c = document.styleSheets[0], stock = {};  return function(s){   this.style = function( css ){var _    if(_ = stock[s]){_.style.cssText += ";" + css;return}    var r = c.cssRules || c.rules,     i = r.length,     S = s.toUpperCase()    while(i--)if(s==r[i].selectorText || S==r[i].selectorText){     (stock[s] = r[i]).style.cssText += ";" + css; return}    c.insertRule?     c.insertRule(s + "{" + css + "}", c.cssRules.length ):     c.cssText += s + "{" + css + "}"   };   return this  } })(); 読みづらいコードで申し訳ない・・・。整形なんて久しくしてないもので・・・ 「insertRuleの引数が面倒。なんでIEはcssTextの要素名が大文字なんだ?」 ってとこの片付けがまだです。 ・このコードを埋め込む<script>タグよりも前に、<style>が少なくとも1つ必要です。  ダミーでいいので<style type="text/css"></style>だけでOK ・$().style()以外の用途が無いこと前提です。ごめんなさい。 ・「-cssText は解析範囲が多いので遅い。」が気になるところですが、よくわからなかったので無視。 ・エスケープや$とかの指摘は、「処理速度向上」という目的外なので、質問者にお任せ。(逃げただけ?)

  • think49
  • ベストアンサー率59% (285/482)
回答No.10

#3,4,9です。 #9でUnicodeエスケープに関するURLを貼り切れなかったので補足を。 今更気が付きましたが、バックスラッシュでもエスケープできるようですね。(Unicodeの方が網羅できる文字種は多いですが) http://www.swlab.it.okayama-u.ac.jp/man/rec-css2/syndata.html#escaped-characters http://hp.vector.co.jp/authors/VA022006/css/syntax.html#escaped-characters

  • think49
  • ベストアンサー率59% (285/482)
回答No.9

一つサンプルコードを書いてみたんですが、長すぎて書ききれなかったのでアドバイスに留めます。 実は私自身が気が付かなかったようなことも他で指摘されまして、その件も含めると大変長くなるので箇条書きにさせていただきます。 ------- - CSSにタグの機構は存在しないので、TAGという名前は望ましくない。適切な名前候補はtype_selector, element_name (CSS2.1仕様の文法規則より)など。 CSS2.1 (W3C) http://www.w3.org/TR/CSS21/syndata#tokenization http://www.w3.org/TR/CSS21/grammar.html CSS2 (Japanese) http://www.swlab.it.okayama-u.ac.jp/man/rec-css2/syndata.html#tokenization http://www.swlab.it.okayama-u.ac.jp/man/rec-css2/grammar.html - CLASSという名前も好ましくない。(小文字の) class は「ECMA-262 3rd Edition」で将来の予約語として定義されており、IE8でエラーが発生する。JavaScriptは大文字小文字を区別するため、CLASSは大丈夫なようだが避けた方が無難と思われる。 7 字句について (Lexical Convention) http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma262r3/7_Lexical_Conventions.html#section-7.5.3 - IE7-では、Array#push は a[a.length] = elm; より数倍遅い。 Script雑感: javascript:遅い push も使い方次第? http://zombiebook.seesaa.net/article/146326121.html - IE7- には getElementsByTagName('*') でコメントノードも拾うバグがある。nodeTypeをチェックしよう。 - function className(str) の名前は望ましくない。 - function className(str) で引き渡せる値はUnicodeエスケープするか正当性検査を行った方がよい。 - cssText は解析範囲が多いので遅い。 - cssText に渡す値はUnicodeエスケープするか、正当性検査すべき。 - もし、querySelectorAll() を使うのならば、関数名を getElementsByClassName() にすべきではない。ネイティブな getElementsByClassName() は生きた(live)ノードリストを返すので名前と機能が一致しない。 - $ の変数名は好ましくない。「ドル記号は機械的に生成されるコード中のみの使用を意図される。(ECMA-262 3rd Editionより)」 7 字句について (Lexical Convention) http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma262r3/7_Lexical_Conventions.html#section-7.6 ------- ものすごい長いですが、まあじっくりと取り組んでみてください。 特にIE7-のバグ関係は対応した方がよいと思います。 Array#push は条件付きコンパイルを利用して、IE7- だけ a[a.length] = elm; な処理に書き換える、という方法が思いつきましたが、そこまでしなくても必要なところで分岐させるだけでいいかも。 cssText の問題は先に挙げたように多岐にわたるので、いっそのことライブラリに渡す方法を変えた方がスマートかもしれません。 例えば、 foo('.test').style({color:'red', backgroundColor: '#fee', border: 'solid 1px #ccc'}); とか。このやり方なら、element.style.property に代入するのも容易でしょう。 for~inを使う場合は、prototypeを拾わないように注意してください。 hasOwnProperty - MDC https://developer.mozilla.org/ja/Core_JavaScript_1.5_Reference/Global_Objects/Object/hasOwnProperty

回答No.8

さ・さ・さ・更に! className の関数の名前もダメ! 適当なのに変えて! あぁ~~~。

回答No.7

再々投稿!ごめんなさい。指摘うけて訂正します。 「無駄に回答が多い」から、「無駄な回答が多い」になってしまった。 window.onload のあとに、 var className = (function ( mode ) {  var alltag = document.getElementsByTagName( '*' );  var stock = [ ];  return function ( css ) {   if( 2 == mode ) {    var tmp = stock[ css ];    if( tmp ) return tmp;   }      var cnt = 0;   var tag;   var result = [ ];      while( tag = alltag[ cnt++ ] )    if( tag.className == css )     result[ result.length ] = tag;      if( result.length ) {    if( 2 == mode )     stock[ css ] = result;    return result;   }   return null;  }; })(2);

回答No.6

れんとう!おばかぶりはっき!さいそくじゃねぇ? var className = (function ( mode ) {  var alltag = document.getElementsByTagName( '*' );  var stock = [ ];    if( mode ) {   var i = 0, t, result = [ ];   while( t = alltag[ i++ ] )    result[ result.length ] = t;      alltag = result;   result = null;  }  return function ( css ) {   if( 2 == mode ) {    var tmp = stock[ css ];    if( tmp ) return tmp;   }      var cnt = 0;   var tag;   var result = [ ];      while( tag = alltag[ cnt++ ] )    if( tag.className == css )     result[ result.length ] = tag;      if( result.length ) {    if( 2 == mode )     stock[ css ] = result;    return result;   }   return null;  }; })(2);

回答No.5

さいしょにことわっておきます。$() はすすめませんよ! でも、おあそびとして、こんなのをかいてみた! className() です! でも、そくどてきには、びりょうか? ぜんかくくうはくは、はんかくにしてちょ! var className = (function ( mode ) {  var alltag = document.getElementsByTagName( '*' );    if( mode ) {   var i = 0, t, result = [ ];   while( t = alltag[ i++ ] )    result[ result.length ] = t;      alltag = result;   result = null;  }  return function ( css ) {   var cnt = 0;   var tag;   var result = [ ];      while( tag = alltag[ cnt++ ] )    if( tag.className == css )     result[ result.length ] = tag;      return result.length ? result: null;  }; })(true);

  • think49
  • ベストアンサー率59% (285/482)
回答No.4

#3です。 #3の一例としてあげたコードですが、try~catch でも良かったですね。 (全角空白は半角空白に置換してください) --------- function getElementsByClassName(elm, className){  var result;  try {   return elm.querySelectorAll('.'+className);  } catch(e) {   elm = elm.getElementsByTagName('*');   // 処理   return result;  } } --------- 構造化プログラミング(一つの入口と一つの出口)的に書くなら、以下のような形でしょうか。 --------- function getElementsByClassName(elm, className){ // 一つの入り口  var result;  try {   result = elm.querySelectorAll('.'+className);  } catch(e) {   result = [];   elm = elm.getElementsByTagName('*');   // 処理  }  return result; // 一つの出口 } --------- > 「RegExpはグローバグオブジェクトなので使用すべきではない」と私は教わりました。 これは「グローバルオブジェクト」に訂正します。

  • think49
  • ベストアンサー率59% (285/482)
回答No.3

処理速度…。確かに、興味ある分野ではあります。 > function className(str){ ネイティブ関数がある場合は、ネイティブ関数を利用した方が高速になります。 IE6等のバージョンの低いブラウザを考慮するなら、関数オブジェクトが定義済みかどうか調べて処理を分けてみてください。 以下は一例です。(全角空白を半角空白に置換してください) ------- var doc = this.document,   result, elm; if('undefined' !== typeof doc.querySelectorAll){  result = doc.querySelectorAll('.foo'); } else {  elm = doc.getElementsByTagName('*'); } ------- document.getElementsByClassName - MDC https://developer.mozilla.org/ja/DOM/document.getElementsByClassName document.querySelectorAll - MDC https://developer.mozilla.org/en/DOM/Document.querySelectorAll document.evaluate - MDC https://developer.mozilla.org/en/DOM/document.evaluate 生きている(live)ノードが欲しいなら、getElementsByClassName() を使い、 生きていない(non-live)ノードで欲しければ、querySelectorAll(), evaluate() を使います。 一般には、生きていないノードの方が高速です。 querySelectorAll() は IE8 から対応しますが、getElementsByClassName() はIE8でも対応しないので注意してください。 evaluate() については、amachangさんが作成されたライブラリがあるのでクロスブラウザは簡単ですが、勉強のためなら使わない方が無難だと思います。 W3C DOM Compatibility - Core http://www.quirksmode.org/dom/w3c_core.html 詳細は書ききれないので、キーワードを元にGoogle検索してください。 > if("."+alltag[i].className == str){ <div class="foo hoge"> の時に対応できません。 この手のコードは getElementsByClassName でGoogle検索すればいくつかのサンプルが手に入りますが、高速化を目指すなら正規表現を使わないようにしてみて下さい。 高速なgetElementsByClassName - 素人がプログラミングを勉強するブログ http://d.hatena.ne.jp/javascripter/20080805/1217912008 > document.getElementsByTagName(RegExp.$1==""?RegExp.$2:RegExp.$1): 「RegExpはグローバグオブジェクトなので使用すべきではない」と私は教わりました。 RegExp.$1 は、match() なら返り値で配列として受け取れます。 > for(var j=0; j<css.length; j++) for文で length を毎回評価するのは効率が良くないので、 for(var j=0,m=css.length; j<m; j++) のようにしてみてください。 > css = css.split(/\:|\;/); わざわざ、splitを使ってまで node.style.property に値を代入するよりは、node.style.cssText に代入した方が簡単ではないでしょうか。 また、この書き方では、content: ";" とか a[title=";"] に誤爆してしまいます…。 style.cssText の使い処に関する考察 - IT戦記 http://d.hatena.ne.jp/amachang/20070730/1185788557 > if(ID){ 「単一ノード or ノードリスト」で処理を分けるぐらいなら、単一ノードも配列の要素として、for文でループさせた方がシンプルに出来ると思います。 実際、jquery.js も prototype.js もそうしています。

3104kita
質問者

補足

お二人ともどうもありがとうございます。 自分の力量では理解できない内容も多く含まれているので、ちょっとお礼を付けるのが遅くなってしまうと思います。しっかり読んで、最終的にはお礼もつけさせて頂きます。すみません。

関連するQ&A