f8g

ポップアップブロック

下の二つはブラウザによって動作が違うみたいというお話でした。

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のリストを見る

http://groups.google.com/group/twitter-api-announce/browse_thread/thread/617bdef9f6b08372?hl=en&pli=1

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 使えないって人は、新しくアカウント作るとそのアカウントで使えたりするみたいです。