画像のレスポンスコードが304の場合、onloadイベントが発生しない件と対策
以下のようなコードを書くと、画像が304を返した場合に、onloadイベントが発生しない
var img = new Image(); img.onload = function(){ console.log("loaded!"); } img.src = "./01.jpg"; // 01.jpg が304を返すと、onloadが発生しない!!
当然と言えば当然なのですが、少しハマったので対策をメモ
先に対策
setIntervalで img.complete をチェックし続ける
img.completeは、画像が読み込み完了したら true を返す
- キャッシュであれ、webから取ってくるのであれ、読み込みが終わったらtrueになるので、304でも読み込み完了を知ることができる
onloadと、img.completeの動き
MacのFirefox16, Safari5.1, chrome23で動作確認した結果はこんな感じ
- onloadは200の時にのみイベントが発生
- img.completeはなんであれ、サーバから結果を受け取ったらtrueがかえってくるっぽい
- ブラウザのキャッシュの場合は未調査
- 後でやる
サンプルコード
rack でこんなの書いて実験した
def self.call(env) data = nil File.open("./01.jpg", "rb") do |f| data = f.read end case env['PATH_INFO'] when '/200.jpg' [200, {"Content-Type" => "image/jpeg"}, [data]] when '/304.jpg' [304, {}, [data]] when '/500.jpg' [500, {}, [data]] when '/404.jpg' [404, {"Content-Type" => "image/jpeg"}, []] when '/' [200, {"Content-Type" => "text/html"}, [(<<-EOS)]] <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <script> var img_check = function(path){ var img = new Image(); img.onload = function(){console.log(path + ":onload");} img.src = path; var id = setInterval(function(){ console.log(path + ":img.complete:" + img.complete); if(img.complete){ clearInterval(id); } }, 100); }; img_check("/200.jpg"); // onloadイベントが発生して、complete:true img_check("/304.jpg"); // onloadイベントが発生しなくて、complete:true img_check("/500.jpg"); // onloadイベントが発生しなくて、complete:true img_check("/404.jpg"); // onloadイベントが発生しなくて、complete:true </script> </head> <body> </body> </html> EOS end end run self
そんな感じ
追記
onerrorも試してみたら、304もonerrorが発生してた