XPathはDOM+JSより速いのか
XPathと、getElementsBy〜の速度比較。
はてなハイク - お絵かきも楽しめるミニブログからclass名がentryである要素を抽出する場合。
console.time('speed'); for(var i=0;i<100;i++)document.getElementsByClassName('entry') console.timeEnd('speed'); console.time('speed'); for(var i=0;i<100;i++)document.evaluate('//*[@class="entry"]',document,null,7,null) console.timeEnd('speed');
DOM:speed: 2ms
XPath:speed: 123ms
単純にクラス名で指定する場合は圧倒的にgetElements〜のほうが速い。しかも生きたNodeList。
では、もう少し複雑な場合。
Bookmarklet - はてなハイクから、class名がprofile-imageで、altがjavascripterであるimg要素を抽出する場合。
console.time('speed'); for(var i=0;i<100;i++)Array.filter(document.getElementsByClassName('profile-image'),function(i)i.alt=='javascripter'); console.timeEnd('speed'); console.time('speed'); for(var i=0;i<100;i++)document.evaluate('//*[@class="profile-image" and @alt="javascripter"]',document,null,7,null) console.timeEnd('speed');
DOM:speed: 36ms
XPath:speed: 109ms
まだDOMのほうが速い。
もっと複雑な場合。
はてなハイク - お絵かきも楽しめるミニブログから、親要素がpで、そのクラス名がusernameで、子のa要素のテキストがjavascripterである要素を取得する場合。
console.time('speed'); for(var i=0;i<100;i++)document.evaluate('//a[../../p[@class="username"] and text()="javascripter"]',document,null,7,null); console.timeEnd('speed'); console.time('speed'); for(var i=0;i<100;i++)Array.filter(document.getElementsByTagName('a'),function(i)i.parentNode.className=='username' && i.textContent=='javascripter'); console.timeEnd('speed');
DOM:speed: 176ms
XPath:speed: 78ms
XPathのほうが速い。
ということで、取得するものが単純な場合はDOMを使って、
Greasemonkeyとかで他人のサイトを弄る場合のように、自由にできないときはXPathを使えばいいと思う。
100回して2秒未満だからそこまで気にする必要ないとは思うけど。
try〜catch文の正しい使い方
try〜catch文は、エラーを処理するときに使う。
たとえば、ユーザーにXPathを入力してもらい、document.evaluateでそれを評価する時、ユーザーが間違ったXPathを入力するかもしれない。
上の内容をそのままコードにすると、
var xpath=prompt('type XPath'); try{ document.evaluate(xpath,document,null,7,null); } catch(e){ if(e.message=='The expression is not a legal expression.')alert('XPath式が間違っています') }
のようになる。
一見これでよさそうだが、これにはひとつ間違いがある。
try文の中で意図しないエラーが発生した場合にもcatch文で吸収されてしまうので、debugが困難になってしまうのだ。
正しくは
var xpath=prompt('type XPath'); try{ document.evaluate(xpath,document,null,7,null); } catch(e){ if(e.message=='The expression is not a legal expression.'){ alert('XPath式が間違っています') }else{ throw e; } }
とするべきである。
こうすると、
var xpath=prompt('type XPath'); try{ document.evaluate(xpath,document,null,7,null));//括弧が多いのでエラーになる } catch(e){ if(e.message=='The expression is not a legal expression.'){ alert('XPath式が間違っています') }else{ throw e; } }
のように、コード自体が間違っている場合にちゃんとエラーが投げられる。
というようなことを思いついたけど、実際にそうやってるコードを見たことが無いし、本当にそんなことをするべきなのかどうかは分からない。
追記:サイ本の98ページあたりにthrowで投げなおすとかそういうことが書いてあった。上のコードは珍しいものじゃなくてごく普通のコードのようだ。
エラトステネスの篩
function primeNumber(n){ var r=[],s=[],tmp; for(var i=2;i<=n;r.push(i++)); do{ s.push(tmp=r.shift()); r=r.filter(function(i)i%tmp); }while(r[r.length-1]>tmp*tmp); return s.concat(r); } primeNumber(20);//[2, 3, 5, 7, 11, 13, 17, 19]