jsで重たい処理をなんとかするはなし

WEB+DB PRESS Tech Meetingに行ってきました - blog.katsuma.tv

JSDeferredについて
重い処理を非同期化させるモデル。その独自ライブラリ(でいいのかな)

と書かれているので、重たい処理についてちょっとだけ。

JSDeferredのようにsetTimeoutでUIスレッドをブロックしないかたちで重たい処理を実行すると便利なのですが、setTimeoutがオーバーヘッドというかタイマの最小分解能の問題で、重たい処理の分割単位を工夫しないと処理完了までの時間が何倍にもなっちゃいます。

前に調べたもの。
setTimeoutとOSのタイマーレゾリューション
jsのyieldをthreadチックに使うことができるのか

あとタイミングよくResigによる記事も。
John Resig - Analyzing Timer Performance


とにかく1回のsetTimeoutで10ms待たされるわけです(Windowsの場合16ms)。だから単純に1万回ループまわすとして、それを毎回setTimeoutにしちゃうとそれだけで10秒かかっちゃうので、何回かループをまわしてからsetTimeoutを呼ばないといけません。

重たい処理の一部を10msくらい実行してsetTimeoutを呼ぶようにループをまわす回数を調整したとすると、重たい処理全体が完了するまでに、なにもしないで素直に実行するときと比べてやっぱり2倍時間がかかっちゃいます。

じゃあ100msくらい重たい処理実行して呼ぶようにすれば10%増で済むからいいんじゃないってわけですが、今度は重たい処理の一部を実行している100msのあいだUIが反応しなくなっちゃうのでそもそもなんでsetTimeout使ってるんだっけという状況に。

どれくらいの時間だったらUIにストレスを感じないのかためしてないのでわかりませんが、とにかくUIがブロックしているように感じない時間と、完了までの時間が伸びちゃう割合と、1回のsetTimeoutを呼び出すまでにかかる実行時間(はクライアントのCPU次第)との兼ね合いでタイマのタイムアウト時間とループをまわす回数を調整する必要がでてきます。めんどくさい!


1,2秒くらいの重たさだとまあそれが4秒くらいになってもがまんできる範囲だと思うので、何も考えずに使えるんですが、ほんとに重たい処理(5秒以上かかるとか)だとちょっとつらいです。


前にHTMLのドキュメントから繰り返し部分をみつけるがちょー重いので(HTMLによるけど5秒overくらい)、やったねまえにamachangがなんか書いてたやつでやってみるぜーとおもってやってみたら、待ちきれないくらい終わらないという結果になって悲しかったのでした。タイマの時間とループ回数の調整すればいけるかもとはおもったけど、作ってたのがextensionだったのでnsIThreadでいーや、みたいなかんじで終了。


というわけで2,3秒くらいだったらいいと思うんですが、重たい処理ぜんぶにこのテクニックが効果的なわけじゃないです。
ちょっとした重たい処理のほか、非同期通信待ちだとぜんぜんsetTimeoutのオーバーヘッド問題とかなしに使えるのでいいですよ。