最近半日潰しましたので残しておきます。
javascriptを普通に記述しているとajaxやnode.jsならば常に気にするので気にならないのですが、思わぬところで非同期処理に出くわしていて気付かずに動作がおかしくなっていたりするので、非同期処理がどこに登場するのか注意しておこうということです。
実際に記述していたコードはforEarch処理内で画像をcanvasに描画等を行ったり色々やっていたので説明用にコードを簡潔にしますが以下のような感じになります。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<script type="text/javascript">
window.onload = function() {
var canvas = document.createElement("canvas");
canvas.height = 500;
canvas.width = 500;
document.body.appendChild(canvas);
var context = canvas.getContext("2d");
var img = new Image();
img.src = "nekobean.png";
img.onload = function () {
context.drawImage(img, 0, 0, 246, 246);
}
}
</script>
</head>
<body></body>
</html>
何も気にしないで記述していたのですが、上ではwindow.onload以外ではimg.onloadが非同期処理でforEach内でimg.onloadを多用していたら読み込むたびに描画される順番が変わる等、挙動がおかしくなっていました。img.onloadが非同期処理ということを失念していた原因によるものでした。
img.onloadを使う際は最初に全て読み込ませておくのが良いかもしれません。
イメージ(動作確認はしていません)
var imagePathList = ["nekobean.png", "nekobean2.png", "nekobean3.png"];
var loadedList = [];
var loadedMap = [];
imageList.forEach(function (imagePath) {
var img = new Image();
img.src = imagePath;
img.onload = function () {
loadedList.push(imagePath);
loadedMap[imagePath] = img;
}
});
// 読み込み監視
var timerId = setInterval(function () {
if (loadedList.length === imagePathList.length) {// 連想配列ではlengthがあてにならない
clearInterval(timerId);
func();
}
}, 100);
function func (){
// 処理を記述
}