07th
Ajaxでのコンテンツ取得に時間がかかっている時に、画面をreloadすると、Firefoxだけreload後にエラー処理が実行された。
例えば、ブラウザ側では
$.ajax( {
type: "get",
url: "test.php",
data: queryString,
success: function(msg){
alert( "Success! " + msg );
},
error: function( msg ) {
alert( "Error! " + msg );
}
} );
で、サーバ側では時間がかかるようにsleep(10)とかしといて、待ってる間にブラウザをreloadしてみます。
すると、XHRがabortされずにエラーハンドラが実行されちゃう。
エラーハンドラが実行されてしまうのは、リロードされるタイミングでreadyStateは4なのに、statusが0(ってか空っぽ)が返ってきて、エラー処理まで到達してしまうからなんだけど、XHRってreload関係なく引き継がれるのか。。。
IEとSafariはよしなにabortしてくれてるみたい。
Firefoxで”readyState”が4なのに”status”が0ってのは仕様らしくて、その場合”responseText”があるかどうかでabortするか判定できる。
ちなみにjQueryの$.ajax関数は対応してないorz
そもそも、まだレスポンスが返ってきていないので、readyStateは1を返すべきですが。
でもreloadのケースの場合、reloadされるタイミングでabortしないといけないので、上の対応をしてもどうしようもない。
ということで、MDCを見たら”onBeforeUnload”というドンピシャなイベントを発見。
$( document ).bind( 'beforeUnload', function() {
xhr.abort();
} );
これでエラーが出なくなりましたー。ヒャッハー!
勉強になりました。
05th
ちょっと早く帰れた日は、HTML5を勉強していくよ!
で、早速Web Workersを触ってみました。
バックグラウンドで処理を実行してくれる上に、マルチスレッドで動いてくれるらしい。しかもマルチコアCPU対応とのこと・・!
これまでのJavaScriptはシングルスレッドなので、setTimeout()使って無理くり並列で処理させていたのが、これでだいぶスッキリできる、、のか?
チュートリアルを参考に、フィボナッチ数列の計算をバックグラウンドで実行してみました。
sample.html内
// workers
var start1 = new Date();
var worker1 = new Worker('job1.js');
worker1.onmessage = function (event) {
document.getElementById('result1').textContent = (new Date() - start1) + "ms, " + event.data;
};
job1.js
function fib( num ) {
var list = {};
var _fib = function( n ) {
if( list[n] ) return list[n];
if( n <= 2 ) return 1;
return list[n] = _fib(n-1) + _fib(n-2);
}
for( var i = 1; i <= num; i++ ) {
postMessage( _fib( i ) );
}
return list;
};
fib( 1000 );
おー何か楽しい。
HTMLとWorkerのやりとりはシンプルで、
Workerから postMessageで HTMLに通知を送り、
HTML側ではWorkerインスタンスの onmessage イベントで通知を受け取れます。
逆にHTMLからWorkerに通知を送ることはできないみたい。
(ストップとかできないのかな?調べよう)
また、HTML側で定義した関数や変数はWorker内で利用できないので、Worker内に全て記述する必要があります。
HTMLとWorkerで相互にデータをやりとりする場合は、
HTML側で
・workerをインスタンス化
・何かトリガーになる関数で、worker.postMessage( value )
・workerからの結果受け取りのためのworker.onmessage( event )
Worker側で
・onmessage( event ) 内で、postMessage( result )
みたいにやれば、相互にやりとりが可能です。
実際に使う場合は、ラッパを作ってしっかり汎用化しないとカオスな感じになりそうですが。。。
ちなみに、WebSocketはまだSafari4でもFF3.5でも未実装みたい。
次はShared Workerを見ていくお。
01st
JavaScriptの高速化はドットの数減らしたり、ローカル変数にキャッシュしたり、再描画がなるべく起きないよう気をつけたりと、地道な作業の連続で成果が出るので、疲れます。。。
とりあえずjQueryのeach()は便利なんですけど、for文で回すようにしよう。
とあるプラグインで使われてたeachをforに変えただけで10%速くなってビックリした。
それはそうと、最近Scalaが気になってしょうがない。
チラッとリファレンス見たところ、キレイで読みやすそうな仕様だった。
Scala勉強会したいなー。
16th
Macに始めから付属しているctagsは古いので、portでインストール。
$ sudo port install ctags
ナイスなことにExuberant Ctagsも一緒にインストールされたみたい。
で、そのままCtagsにかけると、
function() { ... }
は解析されるけど、
var Klass = function() { ... };
Klass.prototype = {
init: function() { ... }
}
のような書き方になってると解析されない。
これでは、Jquery等のライブラリが解析できないので、こちらを参考に、~/.ctagsに以下を記述する。
-regex-javascript=/^[ \t]*(['"]?)([A-Za-z0-9_.]+)\1[ \t]*[:=][ \t]*function[ \t]*\(/\2/I,inner/i
--langmap=javascript:.js
--regex-javascript=/^(.*).prototype *= *(.*)/\1/p,prototype/
--regex-javascript=/^[ \t]*(.*) *: *function/\1/m,method/
--regex-javascript=/^[ \t]*(var | *)(.*) *= *{/\2/o,object/
普通にtagファイルを作る。
$ ctags *.js
taglist.vimで表示するために、.vimrcに以下を追記。
let g:tlist_javascript_settings = 'javascript;v:var;c:class;p:prototype;m:method;f:function;o:object'
これでVimでJSファイルを開いて「:Tlist」を打てば、左側に「クラス、メソッド、関数、オブジェクト」の一覧が表示されます。
1000行超えてくるようなソースを追う場合、超便利です。
ま、Eclipseだとプラグイン入れるだけでリスト出してくれますけど。
16th
いつも忘れちゃうのでメモ。
function extend( self, other ) {
for( var property in other ) {
self[property] = other[property];
}
return self;
}
var Klass = function() {
return function() {
return this;
}
};
Klass.create = function() {
var f = function() {
this.initialize.apply( this, arguments );
};
f.prototype.initialize = function() {};
f.isClass = true;
f.extend = function( other ) {
extend( f.prototype, other );
return f;
};
return f;
};
Klass.extend = function( base_class ) {
if( base_class.isClass ) {
var child = Klass.create();
child.prototype = new base_class;
return child;
} else {
var base = Klass();
base.prototype = base_class;
var child = Klass.create();
child.prototype = new base;
return child;
}
};
使い方。
var Foo = Klass.create();
Foo.prototype = {
initialize: function( name ) {
this.name = name;
},
getName: function() {
alert( this.name );
}
};
var Bar = Klass.extend( Foo ).extend( {
setName: function( name ) {
this.name = name;
}
} );
var f = new Foo( "bob" );
var b = new Bar( "john" );
b.setName( "michel" );
f.getName(); // bob
b.getName(); // michel
10th
Lightboxを作るにあたって
・1枚レイヤを被せるかどうか(後ろを触らせない)で話が変わる
被せるならウィンドウの位置は固定でおk。
被せないなら、後ろを触らせる設計なので、ウィンドウをドラッグ等
移動できるようにしないとダメ。
・汎用性を持たせるなら、ウィンドウの中身は生のHTMLで受け取った方がいいかも
JSONで受け取ると、個別にDOM組み立てることに。
HTMLで受け取ってDOMに追加後、イベント設定する方がいい。
(テンプレート作ってもいいけど、それだと遅くなるので)
・よくあるロード中のアニメーションGIFを画面中央に配置する場合
jQueryを使っているなら、
var loading = $( "<div><img src="./loading.gif" /></div>" ).css( {
position: "absolute",
top: 0,
left: 0
} );
$("body").append( loading );
var _win = $(window);
loading.css( {
top: ( _win - loading.height() ) / 2,
left: ( _win - loading.width() ) / 2
} );
これだと、画像の読み込み前に位置が設定され、ローディング要素のwidthが0になることがある。
なので、こうする。
loading.load( function() {
loading.css( {
top: ( _win - loading.height() ) / 2,
left: ( _win - loading.width() ) / 2
} );
} );
これで、要素が読み込まれた後に位置を設定できる。
03rd
久々にキャパを超えそうな仕事量にボーッとしかけている今週でございますが、ここを乗り越えればリリースも近づくし、給料にもつながるのではグへヘ。
と真っ黒なやる気で頑張るしかないっ!
とにかくやることが大事なんだやることが大事。
そうそう、jQueryのツリービューでいいのないかなーと思ってプラグインを調査してたんですけど、すごい掘り出し物がありましたよ!
jquery.dynatree.js
新しいし全然知名度も無いっぽいんですが、超高機能で使いやすい。
- JSONからツリー構築
- 子階層をAjaxで読み込んで追加できる
- Cookieで開いた状態を保存
- 開閉アイコンとノード部のイベント設定が自由自在
- ツリーにチェックボックスを付けられる
- しかも、子階層まとめてチェックとかもできる
- 全てのオプションをJSONにして一括で指定可能
- スキンが用意されていて、実装とデザインが分離
もはやYUIのツリーに迫る充実ぶり。
JSONで全てのオプションを指定できるのが使いやすいです。
ライセンスもMITライセンスと言うこと無しですね。
単純なツリーならjsTreeなんかで十分かと思いましたが、大規模Webアプリで何か高機能さを求められた場合は、今のところjQueryのプラグインを使うならdynatree一択では・・!
jQueryUIに取り込んでくれたらいいなー。
19th
外部JavaScriptファイルの遅延ロードってIEでちゃんと対応しようとすると、ホントめんどくさいのですが、jQuery使うと超簡単に書けちゃいます。ということを今日知った。
$(document).ready(function() {
$.getScript("JSファイルのパス", function() {
// ロード後に行う処理
});
});
簡単すぎてヤバい。
今日先輩が「jQueryを使わないJavaScriptをすっかり忘れた」と言っていたのですが(いいのか!?)、確かに超便利だけど、ちゃんと仕組みとか勉強しなくなりそうで怖いです。
使うにしても、ちゃんとソース読む癖は付けよう。
18th
OpenSocialの勉強をしようと思って、ドキュメントを眺めていたのですが、やっぱりアプリ作らないとよく分からないので、今月はMixiアプリを作っていこうと思います。
Mixiアプリは仕様が公開されているので、それを見ながら。
JavaScriptアプリをiFrameでMixi上に表示することになるので、JavaScripterにはなんともやりがいがありますね。
ビューはGadgetXMLというXMLに、MXMLみたいに各種ビューの定義とかを書く。
JavaScriptとCSSは外部ファイルで読み込ませてもおk。jQueryとか普通に使えます。
で、JavaScriptでは「opensocial.DataRequest」オブジェクトでSNSからデータを送信したり取得。
取得するデータは「opensocial.DataResponse」オブジェクトで返ってくる。
DataRequestオブジェクトを使って永続化データを操作できる。
今のところ、Mixiから引っ張って来れるのは「ユーザー情報」「マイミク一覧」「参加コミュニティ一覧」ってところで、後はマイミクへの通知ができるみたい。
参加コミュニティからカテゴリ情報が取れればよかったんだけど、ID名, コミュニティ名, トップ画像しか取って来れない。
やはりユーザー情報やマイミクの情報と別のサーバの情報を組み合わせてマッシュアップしてくのがよさげか。
ということで、次はどっかのAPIとマッシュアップしたサンプルを作ってみたいと思いまっす。
