rcmdnk's blog

Comparison of window.onload and jQuery's $(document).ready
Amazon.co.jp: Alligator: OnLoad: デジタルミュージック

JavaScriptでページを読み込み後に何かを行いたいときは window.onload = function()を使ったり、jQueryを使っていれば $(document).ready(function())を使ったりしますが、 これらはちょっと違うものです。

特にjQuery無しで$(document).ready(function)的な事をするのが ちょっと面倒ですがその辺について。

Sponsored Links

window.onload

window.onloadメソッドはonloadイベント発生時に実行されますが、 これはDOMツリーの構築だけでなく、画像や他の全てのデータの 読み込みが完了した時、になります。

また、

1
2
3
window.onload = function() {
  console.log('onload 1');
}

の様にonloadに値を1つ与える形になるので、 この後で

1
2
3
window.onload = function() {
  console.log('onload 2');
}

の様にすると、この最後に指定されたものだけが実行されます(‘onload 2’だけ表示される)。

また、document.body.onloadを指定することも出来ますが、 基本的にwindow.onloadと同じ動作をしますが、 ブラウザによって違う場合があるので使うならwindow.onloadを使うべきです。

$(document).ready

jQueryを使ってる時にはよく使う形。

こちらは画像の読み込みなどは待たず、 DOMツリーの構築が終わった時点で実行されます。

従って、window.onloadで指定されているものよりも先に実行されます。

1
2
3
$(document).ready(function(){
  console.log('ready 1');
});

これは複数書いてもそれら全てが実行されます。

documentreadyも短縮して

1
2
3
$(function() {
  console.log('ready 2');
});

と書くことも出来ます。

また、$が他と衝突するような場合、

1
2
3
jQuery(document).ready(function($) {
  console.log('ready 3');
});

という感じの書き方になります。

また、 onを使って、

1
2
3
$(document).on('ready', function(){
  console.log('ready 4');
});

と書いても同じような動作になります。(が、下に書くように上のものと区別する人があります。)

jQuery無しで$(document).readyな呼び出しをする

window.onloadとjQueryの$(document).readyは 呼び出されるタイミングが違うのと、 複数の処理を別々に与えられるかどうか、の違いが有ります。

タイミングについてはDOMツリーが出来てればJavaScriptでしたいことは出来ることが多いので 画像とかの読み込みを待たずに実行したいことが多いかと思います。

また、別々の場所で必要に応じてやりたいことを追加できる方が便利です。

なので、jQueryがない場合でも$(document).ready的な事をしたいわけです。

これを行うには DOMContentLoadedイベントに対して イベントリスナーを追加します1

1
2
3
document.addEventListener('DOMContentLoaded', function() {
  console.log('DOMContentLoaded');
});

こんな感じ。

DOMContentLoadedは文字通りDOMが出来上がった時で、 jQueryの中のreadyも実際にはDOMContentLoadedを使ったりしして 実装されています2

addEventListenerでの追加は複数行っても全て実行されます3

今はIEやSafariなんかでもこのDOMContentLoadedを使える4 のでこれで$(document).readyと殆ど同じ動作として使うことが出来ます。

onload時に行う物を複数登録する

一方で画像などを全て読み込んだ後にやりたいこともあるかもしれません。

そのような時はwindow.onloadを使えば良いのですが、 これだと1つしか指定できません。

こんな時はjQueryを使えば

1
2
3
$(window).load(function() {
  console.log('onload jquery 0');
});

としたり、

1
2
3
4
5
6
7
$.event.add(window,'load',function() {
  console.log('event add load 0');
});

$(window).on('load', function() {
  console.log('on load 0');
});

みたいに、event.addを使ったり、onを使って書くことが出来、 これらはload時に実行され、 また、複数加えても加えた分だけ実行されます。

これをjQueryなしでやるには

1
2
3
4
5
6
7
8
9
10
11
function ready_func (){
  console.log('ready_func');
}
if( window.addEventListener ){
  window.addEventListener('load', ready_func);
}else if( window.attachEvent ){
window.attachEvent('onload', ready_func);
}
//else{
//  window.onload = ready_func;
//}

見たいな感じでwindowへイベントリスナーを加えたいわけですが、 IEとかだとwindowにはaddEventListenerの代わりに attachEventというメソッドが用意されてるので それを使う様にします。引数もloadonloadで違います5

addEventListenerattachEventでカバーできない物は殆ど無いと思いますが、 もし他でonload =してる場所が無ければ(もしくはここで上書きしても良いのなら)ここでonload =を最後に 加えることも出来ます。

実行される順序

上に書いたとおり、readyの物の方がloadの物よりも先に実行されます。

ではそれらの中では順序はどうなるか、テストしてみます。

test.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
<html>
<head>
<meta charset="utf-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
</head>
<body>
<script>
(function() {
  console.log('IIFE 0')
}());

window.onload = function() {
  console.log('load 0 window.onload = function() {...');
};

window.addEventListener('load', function() {
  console.log('load 0 window.addEventListener("load", function() {...');
});

$(window).load(function() {
  console.log('load 0 $(window).load(function() {...');
});

$(window).on('load', function() {
  console.log('load 0 $(window).on("load", function() {...');
});

$.event.add(window,'load', function() {
  console.log('load 0 $.event.add(window, "load", function() {...');
});

$(document).ready(function() {
  console.log('ready 0 $(document).ready(function() {...');
});

document.addEventListener('DOMContentLoaded', function() {
  console.log('ready 0 document.addEventListener("DOMContentLoaded", function() {...');
});

$(document).on('ready', function() {
  console.log('ready 0 $(document).on("ready", function() {...');
});

$(function() {
  console.log('ready 0 $(function() {...');
});

(function() {
  console.log('IIFE 1')
}());

window.onload = function() {
  console.log('load 1 window.onload = function() {...');
};

window.addEventListener('load', function() {
  console.log('load 1 window.addEventListener("load", function() {...');
});

$(window).load(function() {
  console.log('load 1 $(window).load(function() {...');
});

$(window).on('load', function() {
  console.log('load 1 $(window).on("load", function() {...');
});

$.event.add(window,'load', function() {
  console.log('load 1 $.event.add(window, "load", function() {...');
});

$(document).ready(function() {
  console.log('ready 1 $(document).ready(function() {...');
});

document.addEventListener('DOMContentLoaded', function() {
  console.log('ready 1 document.addEventListener("DOMContentLoaded", function() {...');
});

$(document).on('ready', function() {
  console.log('ready 1 $(document).on("ready", function() {...');
});

$(function() {
  console.log('ready 1 $(function() {...');
});

(function() {
  console.log('IIFE 2')
}());
</script>
</body>
</html>

ここでは

  • load:
    • window.onload = function() {...
    • window.addEventListener("load", function() {...
    • $(window).load(function() {... (jQuery)
    • $(window).on("load", function() {... (jQuery)
    • $.event.add(window, "load", function() {... (jQuery)
  • ready:
    • document.addEventListener("DOMContentLoaded", function() {...
    • $(document).ready(function() {... (jQuery)
    • $(function() {... (jQuery)

を使っています。

ついでに間に即時呼び出し関数式(Immediately-invoked function expression, IIFE)(function() {...も挟んであります。

これを実行すると、Google Chrome(43.0.2357.130, Mac)だと

IIFE 0
IIFE 1
IIFE 2
ready 0 $(document).ready(function() {...
ready 0 $(function() {...
ready 1 $(document).ready(function() {...
ready 1 $(function() {...
ready 0 $(document).on("ready", function() {...
ready 1 $(document).on("ready", function() {...
ready 0 document.addEventListener("DOMContentLoaded", function() {...
ready 1 document.addEventListener("DOMContentLoaded", function() {...
load 0 window.addEventListener("load", function() {...
load 0 $(window).load(function() {...
load 0 $(window).on("load", function() {...
load 0 $.event.add(window, "load", function() {...
load 1 $(window).load(function() {...
load 1 $(window).on("load", function() {...
load 1 $.event.add(window, "load", function() {...
load 1 window.onload = function() {...
load 1 window.addEventListener("load", function() {...

一方、Firefox(39.0, Mac)でみると、 殆ど同じ順序ですが、load 1 window.onload = function() {...load 0 window.addEventListener("load", function() {...の前に来ます。

ちょっと色々テストしてみると

  • readyに関して:
    • まず、$(document).ready、または$(function()等のjQueryのいわゆるdocument readyな物が最初に順に実行される。
    • 次に$(document).on("ready"な物が実行される。
    • その後、"DOMContentLoaded"の物が実行される。
  • loadに関して:
    • window.onloadは最後に書かれたものだけが実行される。
    • window.onloadaddEventListener("load"は、記述された順序で実行される。ただし、window.onloadが2つ以上ある場合、 最初に書かれた所が基準になる。
      • 上の例で、2つ目のload 1 window.onloadが一番最後に書かれたとしても、 load 0 window.onloadの位置が基準になるので、 load 1 window.addEventListener("load"よりも先にload 1 window.onloadが実行される。
    • $(window).load$(window).on("load"$event.add(window, "load"のjQueryな物はこれらの中では記述通りの順序が保たれる。
    • Firefoxではwindow.onloadaddEventListener("load"な物は、 jQueryのloadに関するものの全てより先にあれば先に実行される。
      • もし、jQueryのloadの物が一つでも先にあれば、全てのjQueryのものより後で実行される。
      • この時もwindow.onloadの基準は一番最初の物。
    • Google ChromeではaddEventListener("load"な物は jQueryのloadに関するものの全てより先にあれば先に実行される。
      • もし、jQueryのloadの物が一つでも先にあれば、全てのjQueryのものより後で実行される。
    • Google Chromeではwindow.onloadは何処に書いても全てのjQueryのloadのものより後で実行される。

と言った感じの順序です。

ちょっとごちゃごちゃしてしまいますが、 要するに色々使うと結構前後する可能性があるので 特別な理由がない限りloadready内では統一した書き方で 書くべきだ、と。

Sponsored Links
  1. javascript - $(document).ready equivalent without jQuery - Stack Overflow

  2. 実際にはもっと複雑にDOMContentLoadedが使えないブラウザの場合には それをエミュレートしたりしています。

    その昔、IEとかSafariで使えなかった時とかにはかなり強力な手段でした。

  3. 1
    
    document.addEventListener('DOMContentLoaded', func, false);
    

    みたいに、addEventListenerの最後の引数にfalseを入れてる物も良く見ますが、 最近のブラウザであればこれはデフォルトでfalseで省略可能です。

    Firefox 6とかだときちんと入れないと動かない、ということですが、 流石にもうそこまで考える必要はないと思います。

    EventTarget.addEventListener - Web API インターフェイス MDN

  4. DOMContentLoaded - Event reference MDN

    Can I use… Support tables for HTML5, CSS3, etc

  5. onLoad and onDOMContentLoaded JavaScript Tutorial

Sponsored Links

« ブログとか文章で例として使えるドメインとかIPアドレス MacでApp StoreからXcodeなどのアップデートに失敗した時の対処法 »