javascript:for (var b=document.getElementsByTagName("*"), n = 0; n < b.length; n++) { if (b[n].getAttribute("g:type") == "plusone" && b[n].getAttribute("aria-pressed") != "true") b[n].click() }
2011/06/30
Google+でとりあえず全部+1押しちゃうブックマークレット書いた。
Tagged as: bookmarklet, google+, googleplus, javascript
Bookmarks:
|
2011/05/23
スコープと参照と...
javascriptでhtml内のonclickの内容を書き換えようとしています.. - 人力検索はてなこういうコードになった経緯を考えると、その間違いがなぜ起こったかわかりやすいし、人力検索で回答貰った後で再度間違う事も少ないと思う。
javascriptでhtml内のonclickの内容を書き換えようとしていますが 変更後の関数に変数を渡すと、変更後の関数(load)自体が実行されてしまい、うまくいきません 現在は以下のように、onclickの内容を変更しようとしていますが、 関数を実行させずに、html内のonclickの内容だけ書き換える場合はどのようにしたらいいですか?
document.getElementById('box').onclick = (function(id){ load(id) })(userid);
http://q.hatena.ne.jp/1305849029
おそらくだが、この人はこのコールバック関数登録をループかなんかの中で行おうとしたんじゃないかと(勝手ながら)思った。
<script>このHTMLでfoo1,foo2,foo3をクリックするとどうなるだろう。0,1,2と答えた人は、この質問者と同じ間違いを起こすだろう。答えは全て3が表示される。
window.onload = function() {
var elem = document.getElementsByTagName('a');
for (var n = 0; n < elem.length; n++) {
elem[n].onclick = function() {
alert(n);
}
}
}
</script>
<body>
<a href="#">foo1</a>
<a href="#">foo2</a>
<a href="#">foo3</a>
</body>
これが何故起きて、どう解決すべきかが分かると今後の理解も早いと思う。
ループのインデックスであるnは、コールバック関数から見ると外のスコープにある。つまりコールバック関数が呼び出された時にはループは3回回ってしまっていて、結果どれをクリックしても3が表示される。
じゃぁどうするか。
var elem = document.getElementsByTagName('a');こうじゃない?って答えた人は×。それ何も変わってないから、どれクリックしてもまた3だよって答えた人も×。答えは全て2。
for (var n = 0; n < elem.length; n++) {
var f = n
elem[n].onclick = function() {
alert(f);
}
}
なぜ前回は3が表示されたのか。それはforループが回りきってループを外れる条件に達した、つまり3になったから。ではなぜ今回は2なのか。ループは0,1,2の時にしか実行されなかったから。
わかりますよね。
じゃぁこれ、どうやって個々に0,1,2の値を表示させるのよ...となる。
人によってはeval()使っちゃう人もいるだろうし、昔のコードでは結構見た。未だにそんなコードの保守をやらされる場合もある。出来るだけモダンな書き方したいですよね。
問題はスコープでしたよね。毎回同じスコープが実行されちゃってるのが問題で、コールバック関数から見ると全て同じ変数を見てしまっているのが問題。
そこでループの度にスコープを作ってあげるのです。以下の様なコードを見ることが多いと思います。
(function() {関数を文として扱わず、式として呼び出しているんですよね。最近はこんな書き方もある様です。
// ...
})()
+function() {これで新しいスコープが出来ます。でもこれだけでは解決しません。この作ったスコープで変動しない値を保持してあげます。
// ...
}()
var elem = document.getElementsByTagName('a');変数fにn渡してます。このループが3回実行されると3回スコープが作られ、それぞれにfというスコープ内変数が宣言されます。これにより個々のイベントハンドラから0,1,2が参照出来る様になるという事です。
for (var n = 0; n < elem.length; n++) {
(function() { // ココが決め手
var f = n
elem[n].onclick = function() {
alert(f);
}
})() // ココが決め手
}
ちなみにvar宣言したくない人はよく
for (var n = 0; n < elem.length; n++) {こう書いたりもします。
(function(n) {
elem[n].onclick = function() {
alert(n);
}
})(n)
}
今回の問題、よくカウントダウンタイマを作ろうとして
for (var n = 0; n < 10; n++) {こう書いちゃう人もいます。理屈は同じですよね。気をつけて。
setTimeout(function() {
document.getElementById('timer').innerHTML = '残り' + (10 - n) + '秒'
}, 1000 * n)
}
2010/07/14
JScript.NETでスレッド
CLR上ではC#、VB.NET等が動作しますが、JScript.NETは言語がJavaScriptという事もあって実はC#やVB.NET等と同等に使えない機能がいくらかあります。
JavaScriptは動的言語です。オブジェクトにプロパティを生やしてメソッドにしたり、prototypeを弄ったり、eval()で関数を生成したりも出来ます。つまりコンパイルするとは言えど、型が動的に変えられる言語です。
その為、.NET Frameworkの機能の一つであるDelegateが使えません。.NET FrameworkのThreadはDelegateという関数型拘束によりスレッドを安全に呼び出せる様になっています。この関数型拘束に緩い拘束なJavaScript(JScript)の関数を渡す事は出来ないのです。
MSDNでもJScriptのDelegate利用制限が書かれています。
ThreadStart デリゲートDelegate.CreateDelegate()というメソッドも存在しますが、こちらもJScriptからは利用出来ません。[JScript] JScript では、.NET Framework のデリゲートを利用することができます。ただし、独自に定義することはできません。
http://msdn.microsoft.com/ja-jp/library/system.threading.threadstart(VS.71).aspx
じゃぁDelegateを引数に取るThreadはJScriptから作れないじゃないか!そう思っておられる方が殆どだと思います。
いえ、出来ます。
import SystemC#上で書かれたスレッドインボーカをメモリ内でコンパイルして、それにJScriptの関数、正しくはクロージャを渡します。
import System.Reflection
import System.CodeDom.Compiler
import System.Threading
import Microsoft.CSharp
/**
* createThread()
* @param f thread function
* @param a argument passing to function
* @return thread object
*/
var createThread = (function() {
var source = [
"using System.Threading;",
"public class ThreadInvoker {",
" private Microsoft.JScript.Closure func;",
" private object arg = null;",
" public ThreadInvoker(Microsoft.JScript.Closure func, object arg) { this.func = func; this.arg = arg; }",
" private void invokerThread() { func.Invoke(null, new object[]{this.arg}); }",
" public Thread createInvoker() { return new Thread(invokerThread); }",
"}",
].join("\n");
var cp = CodeDomProvider.CreateProvider("CSharp");
var cps = new CompilerParameters();
cps.ReferencedAssemblies.Add("Microsoft.JScript.dll");
cps.GenerateInMemory = true;
var cr = cp.CompileAssemblyFromSource(cps, source);
var asm = cr.CompiledAssembly;
return function(f, a) {
var tt : Type = asm.GetType("ThreadInvoker");
var args = new System.Object[2];
args[0] = f;
args[1] = a;
return tt.InvokeMember(
"createInvoker",
BindingFlags.InvokeMethod,
null,
Activator.CreateInstance(tt, args),
null);
};
})();
ここから先はCLRなので、どうとでも出来るはずでC#からMicrosoft.JScript.Closureのメソッドを叩く事も出来ます。
これを使えば
var th = createThread(function(v) {こんなコードで
for (var n = 1; n <= 6; n++) {
Thread.Sleep(200);
print("thread" + n + " " + v);
}
}, "foo");
th.Start();
Thread.Sleep(200);
print("main1");
th.Suspend();
Thread.Sleep(200);
print("main2");
Thread.Sleep(200);
print("main3");
th.Resume();
thread1 fooこんな動作をさせる事も出来ます。JavaScript(JScript)でスレッドが使えると色々とやりたくなってきます。JScriptでサーバアプリなんて事も簡単に出来そうですね。
main1
main2
main3
thread2 foo
thread3 foo
thread4 foo
thread5 foo
thread6 foo
ちなみに、このcreateThread()を使うと、ウェブサーバなんかも書けたりします。試しに書いてみたらコードの少なさ(createThreadは除いて)に少し驚きました。JScript.NET & C# ばんざい!
import Systemマルチスレッドウェブサーバです。カッコイー!
import System.Reflection
import System.CodeDom.Compiler
import System.Threading
import Microsoft.CSharp
/**
* createThread()
* @param f thread function
* @param a argument passing to function
* @return thread object
*/
var createThread = (function() {
var source = [
"using System.Threading;",
"public class ThreadInvoker {",
" private Microsoft.JScript.Closure func;",
" private object arg = null;",
" public ThreadInvoker(Microsoft.JScript.Closure func, object arg) { this.func = func; this.arg = arg; }",
" private void invokerThread() { func.Invoke(null, new object[]{this.arg}); }",
" public Thread createInvoker() { return new Thread(invokerThread); }",
"}",
].join("\n");
var cp = CodeDomProvider.CreateProvider("CSharp");
var cps = new CompilerParameters();
cps.ReferencedAssemblies.Add("Microsoft.JScript.dll");
cps.GenerateInMemory = true;
var cr = cp.CompileAssemblyFromSource(cps, source);
var asm = cr.CompiledAssembly;
return function(f, a) {
var tt : Type = asm.GetType("ThreadInvoker");
var args = new System.Object[2];
args[0] = f;
args[1] = a;
return tt.InvokeMember(
"createInvoker",
BindingFlags.InvokeMethod,
null,
Activator.CreateInstance(tt, args),
null);
};
})();
import System.Net
import System.Net.Sockets
var listener = new System.Net.Sockets.TcpListener(IPAddress.Parse("127.0.0.1"), 8080);
listener.Start();
while (true) {
createThread(function(client) {
var stream = client.GetStream();
var buf = new System.Byte[client.ReceiveBufferSize];
var bytesRead = stream.Read(buf, 0, buf.length);
var str = [
"HTTP/1.0 200 OK",
"Content-Type: text/html",
"",
"<html><body>",
"<b>hello world</b>: " + (new Date).toString(),
"</body></html>",
].join("\r\n");
var bytes = System.Text.Encoding.Default.GetBytes(str);
stream.Write(bytes, 0, bytes.length);
stream.Close();
client.Close();
}, listener.AcceptTcpClient()).Start();
}
2009/10/13
javascriptで動くtwitter streamクライアントを作るならばmultipart/mixedを使うべき
- サーバサイドでステータス更新をFIFOに溜め込む
- クライアントからリクエストをブロック(long poll)しFIFOからステータスを送出する
- クライアントサイドでlong pollを行い画面を更新する
- 再度サーバへリクエストを投げる
ここで使える!と思ったのがmultipart/mixedです。
multipart/mixedはboundaryで区切られたボディ部を繰り返し送出する際に用いられる仕組みで、実はXHR(XMLHttpRequest)はこのmultipart/mixedなレスポンスを受け取る事が出来る。
受け取るとは言っても、実際にはreadyStateが変化する...でしかないのだけど、これを扱うのに良いライブラリがある。
diggで使われているDUI.jsとStream.jsです。
digg's stream at master - GitHubこのstreamライブラリは内部でreadyStateが3になるのを待ち、タイマを張ってboundaryを監視するものです。つまり1 body部を扱う事になるので、使う際にはmime typeを指定する事になります。
Alpha repository for DUI.Stream. When it stabilizes, it will be merged back into DUI
http://github.com/digg/stream
var s = new DUI.Stream();この仕組みを使って、twitterからのストリームをクライアントにmultipart/mixedで送出し、かつクライアントも接続を保持したままレスポンスを受け取るのです。接続を切らないので、ほぼタイムロス無しのリアルタイムと言って良いでしょう。
s.listen('text/html', function(payload) {
...
});
s.load('/push');
今日はこれをsinatraを使って実装してみました。出来れば一度動かしてみて下さい。これまでリクエストを繰り返し送っていたアプリケーションと比べてスムーズにデータを受け取っているのが分かって頂けるかと思います。
上記diggのライブラリを作業フォルダのstatic/jsフォルダ配下に置き、以下のファイル(fast-twitter-stream.rb)を作業フォルダ直下に置きます。
require 'rubygems'元となったコードはyoupyさんの物を参考にさせて頂きました。
require 'sinatra'
require 'json'
require 'tweetstream'
require 'pit'
# doesn't work on thin and webrick
set :server, 'mongrel'
set :public, File.dirname(__FILE__) + '/static'
config = Pit.get("twitter.com", :require => {
"username" => "your username in twitter",
"password" => "your password in twitter"
})
get '/' do
<<HTML
<html> <head>
<title>Server Push</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js"></script>
<script type="text/javascript" src="/js/DUI.js"></script>
<script type="text/javascript" src="/js/Stream.js"></script>
<script type="text/javascript">
$(function() {
var s = new DUI.Stream();
s.listen('text/javascript', function(payload) {
var status = eval(payload);
$('#content').append('<p>' + status.text + '</p>');
});
s.load('/push');
});
</script>
</head>
<body>
<h1>Server Push</h1>
<div id="content"></div>
</body>
</html>
HTML
end
get '/push' do
boundary = '|||'
response['Content-Type'] = 'multipart/mixed; boundary="' + boundary + '"'
MultipartResponse.new(boundary, 'text/javascript')
end
class MultipartResponse
def initialize(boundary, content_type)
@boundary = boundary
@content_type = content_type
end
def each
TweetStream::Client.new(config[:username], config[:password]).sample do |status|
yield "--#{@boundary}\nContent-Type: #{@content_type}\n(#{status.to_json})"
end
end
end
ブラウザから"http://localhost:4567/"にアクセスすると、もの凄い勢いでステータスが追加されていくのが分かるかと思います。しかも切断していないのでかなり高速です。
お試しの効果には個人差があります。
このmultipart/mixed、結構使えるなーと思いました。得にリアルタイムな画像ストリーミングとして送出したり、リアルタイム電光掲示板の様な物にも使えるかと思います。
今回のサンプルもgithubに置いてあります。
mattn's fast-twitter-stream at master - GitHubよろしければご参考までに。
fast twitter stream client using multipart/mixed.
http://github.com/mattn/fast-twitter-stream
JavaScript & Ajax プロが教える“本当の使い方”



![Validate my RSS feed [Valid RSS]](http://mattn.kaoriya.net/images/valid-rss-rogers.png)

