iPadのSafariは、2カ所から画像のメモリに接続するとリークしガベージされない。
iOS、3.2、4.2.1、どちらも起きる。
例えば、2つのimg要素が同じsrcを設定すると、その画像リソースはページのリロードまで2度と離されない。
以下のサンプルは、画像ロードが途中で停止し、以降は新しい画像を表示できない。
デスクトップのブラウザのように、別のimg要素でプリフェッチして、他のimg要素で表示する手法は使えない。
// imagesにsrcのリストを用意
var elmImage = document.body.appendChild(document.createElement('img'));
var elmOther = document.createElement('img');
(elmImage.onload = function(){
document.title = images.length;
// 2カ所からリンク
elmOther.src = elmImage.src;
if(images.length)
elmImage.src = images.shift();
})();
またLast-Modifiedなどで、ブラウザがキャッシュし、そのリソースを使った時もリークする。
ブラウザのキャッシュがちょうど一杯になるか越えるぐらいの画像を用意して、以下を2度実行すると、最初のサンプルと同様に途中で停止する。
(画像が多すぎるとサイクルしてキャッシュヒットしなくなり、少なすぎると停止するまでの量にならないので実験する場合は注意)
この挙動は、yubichizで同じ箇所を繰り返し表示させているとロードが停止する現象などで確認できる。
// imagesにsrcのリストを用意
// images = images.concat(images); // これで2周しても可
var elmImage = document.body.appendChild(document.createElement('img'));
(elmImage.onload = function(){
document.title = images.length;
if(images.length)
elmImage.src = images.shift();
})();
いろいろテストする場合は、iPadの設定からSafariのキャッシュをクリアし、Safariを再起動してから行うこと。
img要素をたくさん生成できない問題の回避方法。使い終わったら、srcを空にする(data uri使わなくても大丈夫だったとおもう)。
canvasを併用していろいろやる方法は基本的に遅い。
data uri(base 64)は、もっと遅い。
密に処理が実行されてしまうのを避けるため、二つのかたちがあるとのこと。
下のデモ。
throttleは、0.5秒ごとに点の位置が変わる。
debounceは、0.5秒いると赤くなる。
ひとつ目は一定間隔以内の呼び出しは間引いて無視する方法。
イベントの発生頻度が多く、処理が重い場合に使う。

Function.prototype.throttle = function(threshold, alt){
threshold = threshold || 100;
var me = this;
var last = Date.now();
return function(){
var now = Date.now();
if(now - last < threshold){
if(alt)
alt.apply(this, arguments);
return;
}
last = now;
me.apply(this, arguments);
};
}
もうひとつは、一定間隔呼び出されなかったときに、はじめて処理を実行する方法。
補完や通信、ツールチップ、マウスアウトでメニューを閉じる場合などに使う。

Function.prototype.debounce = function(threshold){
var me = this;
var timeout;
return function(){
var self = this;
var args = arguments;
if(timeout)
clearTimeout(timeout);
timeout = setTimeout(function(){
me.apply(self, args);
timeout = null;
}, threshold || 100);
};
}