次の(脆弱な)JavaScriptコードを検討してください。
_var img = new Image;
img.src = "data:image/png;base64,..."; // Assume valid data
// Danger(?) Attempting to use image immediately after setting src
console.log( img.width, img.height );
someCanvasContext.drawImage( img, 0, 0 );
// Danger(?) Setting onload after setting src
img.onload = function(){ console.log('I ran!'); };
_
質問
onload
コールバック(srcの変更後に設定)を呼び出す必要がありますか?実験的試験
同様のコードで シンプルなテストページ を作成しました。 Safariでの最初のテストでは、HTMLページをローカルで開いて(_file:///
_ url)、サーバーから読み込むことで、すべてが機能していることを示しました:高さと幅が正しく、キャンバス描画が機能するonload
も起動します。
Firefox v3.6(OS X)では、ブラウザーの起動後にページをロードすると、設定直後に高さ/幅が正しくないことが示され、drawImage()
が失敗します。 (ただし、onload
ハンドラーは起動します。)しかし、ページを再度ロードすると、設定直後に幅/高さが正しく表示され、drawImage()
が機能します。 FirefoxはデータURLのコンテンツを画像としてキャッシュし、同じセッションで使用するとすぐに利用できるように見えます。
Chrome v8(OS X))Firefoxと同じ結果が表示されます。画像はすぐには使用できませんが、データURLから非同期に「ロード」するには時間がかかります。
上記のブラウザが動作するか動作しないかの実験的証拠に加えて、これがどのように動作するかについての仕様へのリンクが大好きです。これまでのところ、私のGoogle-fuはタスクに対応していません。
安全にプレイする
上記が危険な理由を理解していない人のために、安全のために次のような画像を使用する必要があることを知ってください。
_// First create/find the image
var img = new Image;
// Then, set the onload handler
img.onload = function(){
// Use the for-sure-loaded img here
};
// THEN, set the src
img.src = '...';
_
これがどのように想定されるかについての仕様を誰もまだ見つけていないので、どのようにdoesに満足する必要があります振る舞います。以下は私のテストの結果です。
|画像データは使用可能です| src の後に設定されたonloadコールバックを行います| srcを設定した後? |変更はまだ呼び出されますか? ------------ + -------------------------- --- + ------------------------------------- Safari 5 |はい|はい ------------ + ----------------------------- +- ------------------------------------ Chrome 8 | **いいえ**(最初のページの読み込み)、しかし|はい FireFox 3.6 |はい(キャッシュ済み)| ------------ + ----------------------------- +- ----------------------------------- IE8 |はい(32kBデータ制限)|はい ------------ + ----------------------------- +- ------------------------------------ IE9b |はい| **いいえ** ------------ + --------------------------- -+ -------------------------------------
要約すれば:
onload
イベントを待つ必要があります。onload
を設定した後にsrc
ハンドラーを設定できず、呼び出されることを期待できません。誰かがこれについて議論している仕様を見つけることができるならば、私は彼らの答えを代わりに喜んで受け入れます。
ブラウザのレンダリングエンジンに制御を戻した後、テストはFF 4b9およびChromium 8.0.552.237でtrue
を報告します。これらの部分を変更しました:
img.onload = function(){ // put this above img.src = …
document.getElementById('onload').innerHTML = 'yes';
};
img.src = img_src;
…
window.setTimeout(function () { // put this inside setTimeout
document.getElementById('wh').innerHTML = (img.height==img.width) && (img.height==128);
}, 0);
更新:はい、この「回答」はコメントのようなものですが、指摘したいだけです。そして、テスト後、再現可能な結果が得られます。
setTimeout
なしで、両方のブラウザで最初にページを開いたときにfalse
を、ヒットした後にのみtrue
を取得します F5。キャッシュを明示的にクリアした後、両方ともリロード後に再度false
と言います。setTimeout
を使用すると、幅/高さのテストは常にtrue
になります。どちらの場合も、ページをリロードした後に初めて画像が表示されます。