ポップアップブロック
下の二つはブラウザによって動作が違うみたいというお話でした。
button.onclick = function(){ window.open(url); };
button.onclick = function(){ setTimeout(function(){ window.open(url); }, 1); };
http://arikui.github.com/js/popupblock.html
<html> <head> <title>test</title> <script type="text/javascript"> function execute(){ window.open("popupblock.html"); } function click1(){ execute(); } function click2(){ setTimeout(function(){ execute(); }, 1); } function click3(){ var req = new XMLHttpRequest; req.onreadystatechange = function(){ if(this.readyState == 4){ execute(); } }; req.open("GET", "popupblock.html"); req.send(); } </script> <body> <button onclick="click1();">click</button> <button onclick="click2();">setTimeout</button> <button onclick="click3();">XMLHttpRequest</button> <button onclick="document.getElementsByTagName('button')[0].click();">call first button's event</button> </body> </html>
クロージャ, call, apply の今
もう1年も経っていた。
http://d.hatena.ne.jp/arikui/20091021
久々に気になったのでちょっと直して測りなおしました。計測PCも違ってたりしますが、多分傾向は同じ。
単位はナノ秒。
fx3.6
plain 57 closure 218 call 230 apply 520 apply arguments 1700 apply this value 262 closure 3 nest 516 call 3 nest 518
クロージャもcallも大して差がなくなった。argumentsをapplyすると一気に遅い。
fx4b8
plain 13 closure 114 call 137 apply 211 apply arguments 322 apply this value 107 closure 3 nest 395 call 3 nest 360
argumentsのapplyが速くなった。コンテキスト辿るのも速くなった感じがする。
ie9b
plain 410 closure 2443 call 1733 apply 2043 apply arguments 4427 apply this value 1867 closure 3 nest 3886 call 3 nest 4143
クロージャが遅いみたいだけど、callを重ねると大差なくなる。
opera10.7
plain 35 closure 523 call 558 apply 195 apply arguments 1135 apply this value 672 closure 3 nest 1583 call 3 nest 1835
配列のapplyが何故か速い。
safari5
plain 44 closure 960 call 993 apply 962 apply arguments 1131 apply this value 1060 closure 3 nest 2829 call 3 nest 2881
平均的。
chrome 9
plain 24 closure 79 call 266 apply 120 apply arguments 285 apply this value 286 closure 3 nest 131 call 3 nest 713
callがやけに遅い。
ImageData callback
イマドキなデータのやりとり。
server.php
<?php $q = str_split($_GET["q"]); $data = array(); foreach($q as $c){ $n = ord($c); if($n > 255){ exit("cannot support charactor '" . $c . "'"); } else{ $data[] = $n; } } $v_n = count($data); $px_n = ceil($v_n / 3); $img = imagecreate($px_n, 1); $i = 0; $x = 0; while($x < $px_n){ $px = imagecolorallocate( $img, array_key_exists($i++, $data) ? $data[$i - 1] : 0, array_key_exists($i++, $data) ? $data[$i - 1] : 0, array_key_exists($i++, $data) ? $data[$i - 1] : 0 ); imagesetpixel($img, $x++, 0, $px); } header("Content-type: image/png"); imagepng($img); imagedestroy($img); ?>
client.html
<html> <head> <title>client</title> </head> <body> <canvas></canvas> <script type="text/javascript"> var canvas = document.getElementsByTagName("canvas")[0]; var context = canvas.getContext("2d"); var data = {a: 1, b: 2, c: 3}; var img = new Image; img.onload = function(){ var w = canvas.width = img.naturalWidth; var h = canvas.height = img.naturalHeight; context.drawImage(img, 0, 0); var data = context.getImageData(0, 0, w, h).data; console.log(ImageDataToData(data)); }; img.src = "server.php?q=" + encodeURIComponent(JSON.stringify(data)); function ImageDataToData(data){ var d = [data[i] for(i in data) if((i * 1 + 1) % 4 && data[i])]; var str = String.fromCharCode.apply(null, d); return JSON.parse(str); } </script> </body> </html>
利点なし。
Selectorの話し
firefox | GChrome | IE8 | opera | |
#foo .bar | 636 | 512 | 432 | 551 |
.bar | 493 | 262 | 435 | 336 |
#foo a | 597 | 320 | 390 | 561 |
#foo * | 619 | 280 | 384 | 530 |
span.bar | 386 | 170 | 240 | 217 |
<html> <head><title>test</title> <script type="text/javascript"> window.onload = function(){ var selectors = [ "#foo .bar", ".bar", "#foo a", "#foo *", "span.bar", ]; var test = function(selector){ return function(){ var s = new Date; for(var i = 0; i < 10000; i++) document.body.querySelectorAll(selector); console.log(selector + ": " + (new Date - s)); }; }; for(var i = -1, selector; selector = selectors[++i];) setTimeout(test(selector), 1); }; </script> </head> <body> <div id="foo"> <a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"> <a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"> <a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"> <a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"> <a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"> <a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"> <a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"> <a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"> <a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"> <a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"> <a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"> <a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"> <a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"> <a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"> <a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"> <a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"> <a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"> <a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"> <a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"> <a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"></a><a class="bar"> </div> </body> </html>
WSHでウェブページをHTMLDocumentで取得
いろいろ調べたけどあんまりうまくいかなかったりしたので、ちょっとややこしい方法。
ウェブページの取得
MSXML で。
var XmlHttp = WSH.CreateObject("MSXML2.XMLHTTP"); XmlHttp.open(method, url, false); XmlHttp.send(data);
文字コード変換
変換にはここの ADOS_Decode がそのまま使える。
http://homepage2.nifty.com/nonnon/SoftSample/VB.NET/SampleModADOS.html
function toUnicode(bytes, charset){ var stream = WSH.CreateObject("ADODB.Stream"); stream.Open(); stream.Type = 1; // ADODB.StreamTypeEnum.adTypeBinary stream.Write(bytes); stream.Position = 0; stream.Type = 2; // ADODB.StreamTypeEnum.adTypeText if(charset) stream.Charset = charset; var result = stream.ReadText(); stream.Close(); stream = null; return result; }
自動の精度があんまりよくない気がするので、文字コード判定。
var charset, matches; if(matches = XmlHttp.getResponseHeader("Content-Type").match(/charset=(.+)/)) charset = matches[1]; else if((matches = XmlHttp.responseText.match(/<meta[^>]+content="[^\"]+charset=([^>]+)"/))) charset = matches[1];
ADODB.Stream に Binary で流し込むので、 XmlHttp.responseBody を渡す。
toUnicode(XmlHttp.responseBody, charset)
HTMLDocument を作る
htmlfile から HTMLDocument を作る。この際、ソースに script タグがあると警告が出てくるようなので、その部分は消しておいた方がいい。
var source = this.toUnicode(XmlHttp.responseBody, charset) .replace(/(<script)|(<\/script>)/ig, "") .replace(/<\/title>/, [ '</title>', '<meta http-equiv="X-UA-Compatible" content="IE=edge" />' ].join("")); var document = WSH.CreateObject("htmlfile"); document.open(); document.write(source); document.close();
ちなみに
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
を設定すると IE の最新のバージョンで読み込む。IE8 が入っていれば Selector が使える、……かと思いきや使えない模様。 document.documentMode = 8 にはなるのに。あと、たまに eval も使えなくなったりしてよく分からない挙動をする。
何かもっと楽な方法ありそうなんだけどな。
LDR のピンを最後に追加するようにするのと, 100 件溜まったら自動で開く Greasemonkey
http://userscripts.org/scripts/show/61268
LDR よく分からないのと, onload 書き換えとか色々やな感じではあるけど, 動作的に問題はなさそう.
// ==UserScript== // @name LDR pin push // @namespace d.hatena.ne.jp/arikui // @include http://reader.livedoor.com/reader/ // ==/UserScript== var w = unsafeWindow; var _onload = w.onload; w.onload = function(){ _onload(); var pin = w.pin; var pin_add = pin.add; pin.add = function(url,title){ if(this.has(url)) return; pin.pins.unshift = pin.pins.push; pin_add.apply(this, arguments); if(pin.pins.length == 100) pin.open_group(); }; }
WSHでTwitterのリストを見る
var username = "username"; var password = "password"; var api_url = "http://twitter.com/ユーザ名/lists/リスト名/statuses.json"; var created_at = null; while(true){ var data = getData(); puts(data, created_at); created_at = data[0].created_at; WSH.Sleep(30000); } function getData(){ var XmlHttp = WScript.CreateObject('MSXML2.XMLHTTP'); XmlHttp.open("GET", api_url, false, username, password); XmlHttp.send(null); var data; eval("var data = " + XmlHttp.responseText); if(data.error){ WSH.Echo(data.error); WSH.Quit(0); } return data; } function puts(data, stop){ var s = []; for(var i = 0; i < data.length; i++){ if(data[i].created_at == created_at) break; s.push(data[i].user.screen_name + ": " + data[i].text); } s.reverse(); for(var i = 0; i < s.length; i++) WSH.Echo(s[i]); if(s.length) WSH.Echo(""); }
今のところ1時間に150リクエストと制限があるようなんで、30秒間隔ぐらいがいいみたいです。
あと、lists 使えないって人は、新しくアカウント作るとそのアカウントで使えたりするみたいです。