愛と勇気と缶ビール

ふしぎとぼくらはなにをしたらよいか

iPhone/Androidにタッチ!

stats.js (https://github.com/mrdoob/stats.js) という、JavaScriptfpsもどきの値を出すライブラリをiPhone/Androidで試していた時に気づいたんだけど、iPhone/AndroidWebKitではデフォルトのスクロール中はsetIntervalの監視が無効になっているっぽい。

具体的には、例えば setInterval(function() { count++; }, 1000); みたいなことをやっているページがあってとして

1. タッチ開始
2. 指を動かす
3. タッチ終了
4. 慣性スクロール

の流れで、4.が完全に終わるまでcountの値は変わらない。また、実行キューに入っていたものがスクロール後に一気に実行されるというわけでもない。完全にtimerが止まっている。

一瞬「指を置いて動かしている間はJSの実行は全く行われないのかな?」と思ったが、それだとtouchmoveとかにbindしたevent handlerが全く実行されないことになってしまう。そんなアホな。

そんなアホなことは流石になかったが、はて。私たちは、touch eventのevent handlerの実行だけが許されたイヌカレー空間に居る、とでもいうのだろうか。

setInterval及び各event handler(touchstart, touchmove, touchend, scrollにbind)の中でxhrでリクエスト投げて眺めてみると、

1. タッチ開始 -> touchstart, timer停止
2. 指を動かす -> touchmove
3. タッチ終了 -> touchend (iOS: この時点でtimer再開)
4. 慣性スクロール -> scroll (Android: scrollが完全に終了後 timer再開)

のような関係になっているように見える。iOSがタッチ終了時にtimer再開していると予想したのは、setIntervalによってenqueueされていた処理が一気に実行されたっぽい感じにスクロール終了後バラバラッとリクエストが来たので。

手元にあるiPhone 3GS(iOS 4.2.1)とHTC evo(Android 2.2.1)でしか比べてないが、iOSAndroidでは同じ指の動かし方をしても全くeventの発行のされ方が違っていて

iOSのほうは

touchstart
touchmove
touchmove
touchmove
touchmove
touchmove
touchmove
touchend
scroll

という感じにeventが発行されるのに対して、

Androidだと

touchstart
touchmove
touchmove
touchend
scroll
scroll
scroll
scroll
scroll
scroll
scroll
scroll
scroll
scroll
scroll
scroll
scroll
.
.
.

みたいな感じでtouchmoveの数がiPhoneよりかなり少なく、scroll eventおよび慣性スクロールによる移動量がiOSのそれよりかなり大きい。前者はHW的な感度の問題なのか、それともブラウザ側の問題なのか…

eventの発行のされ方がここまで違うと、touchmove or scroll eventの粒度の細かさに依存した処理を書いてしまうと「あれれー、おかしいなー?おじさん、iPhoneAndroidで動作が全然違うよ?」みたいなコナン君になってしまうかもしれない。