HTMLやJavaScriptのデバッグ
ソフトウェア開発を進める作業段階では,
- 設計どおりに動作しない!
- 出力結果がおかしい!
など,多く不具合に悩まされる.このような不具合は,主としてプログラムが正しく書かれていないことに起因するものがほとんどであり,このことをバグがある(bug: 小さな虫,という意味)という.ソフトウェア開発においては,この「バグ」を発見したり修正したりする作業が不可欠である.
特に,HTMLやJavaScriptは(C言語などのコンパイラ言語とは違って)実行してみるまで文法的なエラーが分からないといったデメリットもある.JavaScriptは(良い意味でも悪い意味でも)自由すぎる言語なので,何の支援もなしにデバッグ作業を行う(de-bug: bugを取り除く)と相当に苦労する.
ここでは,chromium-browserやFirefoxなどのブラウザに搭載されているデバッグ支援ツールを利用した典型的なデバッグ方法を記載するので,各自うまく使いこなそう.
デバッグ支援ツールの起動
本講義サイトのあちこちに記載しているが,chromium-browserやFirefoxの場合,
- F12キー
- または Ctrl+Shift+I キー
でデベロッパツール(Firefoxだと開発ツールという名称)を開くことができる.
- chromium-browserの場合
- Firefoxの場合
これを上手く利用すると,デバッグを効率的に行うことができる.
consoleを使いこなす
console.log
console.log('コンソールに表示する');
これを(ブラウザ経由で)実行すると,デベロッパツールのconsole
タブに表示される.
このように,プログラム(スクリプト)内の適当な場所にconsole.log()
を挟み,実行中にconsole
タブでその内容を確認することがまず第一の基本となる.
console.error, console.warn
エラーや警告などの用途によって,出力先を分けることもできる.
console.error('エラーの場合');
console.warn('警告の場合');
この場合,console
タブでは色分けされて(かつアイコンも追加されて)表示される.
console.table
配列の中身を確認したい場合は,console.logよりもconsole.table
がお勧め.
var ary = [{ name1: "sato", name2: "suzuki", name3: "tanaka" }];
- console.logの場合
console.log(ary);
- console.tableの場合
console.table(ary);
console.trace
関数の呼び出し元をトレースできる.
(function first() { function second() { function third() { console.trace(); } third(); } second(); })();
ブレークポイントを使う
ブレークポイント(break point)を設定すると,プログラム実行時に割り込んで停止や再開を行うことができる.
ブレークポイントの設定法
デベロッパツールを使う方法と,JavaScriptプログラムを直接,編集して設定する方法がある.
例えば,次のようなJavaScriptプログラムに対し,
2 3 4 5 6 7 8 9 10 11 12 13 | var ary = [ ['A','B','C'], ['D','E','F'], ['G','H','I'] ]; for (var i = 0; i < ary.length; i++){ for (var j = 0; j < ary[i].length; j++){ document.write(ary[i][j] + ' '); } document.write("<br />"); } |
デベロッパツールのSource
タブを開き,「停止させたい該当の行をクリック」すると,以下のようにブレークポイントが設定される.
あるいは,スクリプト内(の止めたい箇所)に直接,debugger;
という記述を加えても良い.
5 6 7 8 9 10 11 | ['G','H','I'] ]; debugger; for (var i = 0; i < ary.length; i++){ for (var j = 0; j < ary[i].length; j++){ } |
どちらの場合でも,ページをリロードすると設定したブレークポイントで処理が止まる.
ブレークポイントからの処理再開
さて,ブレークポイントで処理を止めたら,Source
タブの右側にあるボタン群を利用して特別な実行を行うことができる.(プログラム実行の流れに介入して,進め方をコントロールすることができる)
処理再開
次のブレークポイントまで,もし無ければ最後まで処理を続行する.
ステップオーバー
現在のステートメントを実行してから次のステートメントで停止する.もし,現在のステートメントが関数呼び出しであった場合には,その関数全体を実行し,関数呼び出し後の次のステートメントで停止する.
ステップイン
現在のステートメントを実行してから次のステートメントで停止する.現在のステートメントが関数呼び出しであった場合,その関数に処理が遷移したところで止まる.
ステップアウト
現在の関数の外まで実行する.関数が入れ子になっている場合には1つ上のレベルまで進んだら止まる(現在の関数を抜けた段階で止まる).
プログラム実行中の値の変更
さて,上記のサンプルでは,配列ary
に
Array(3) 0: Array(3) 0: "A" 1: "B" 2: "C" 1: Array(3) 0: "D" 1: "E" 2: "F" 2: Array(3) 0: "G" 1: "H" 2: "I"
とセットされるはずである.これは,デベロッパツールSource
タブ右側の,Scope
から確認することができる.
これを変更してみよう.Scope
に表示されているプロパティのところでダブルグリックすると,直接,値を変更できる.
A〜Iをそれぞれ,J〜Rに変更して「処理再開」すると,実行結果もこれに応じて変わるはずである.
ブレークポイントまとめ
以上のように,任意の箇所にブレークポイントを設定し,ステップ実行しながら動作確認,場合によっては変数の値を変更してみる,などのデバッグが行えるようになる.
さらには,他の班員が作ったモジュールをテストする際,あえてイレギュラーな値を渡して動作確認してみる,といったこともできるので,ぜひ使いこなせるようになろう.
Socket.ioを使ったプログラムの場合
サーバ(Node.js)側
起動時にDEBUG
環境変数にsocket.io*
を設定しておくと,サーバ動作中にいろいろログが表示されるようになる.
$ DEBUG=socket.io* node main.js socket.io:server initializing namespace / +0ms socket.io-parser encoding packet {"type":0,"nsp":"/"} +0ms socket.io-parser encoded {"type":0,"nsp":"/"} as 0 +1ms socket.io:server creating engine.io instance with opts {"path":"/socket.io","initialPacket":["0"]} +4ms socket.io:server attaching client serving req handler +17ms Server started on port:6004 ...
クライアント側
HTML5から導入されたlocalStorage
を使うとよい.
スクリプトの中(先頭付近でよい)に
localStorage.debug = 'socket.io-client:socket';
という行を挿入しておくと,ブラウザのConsole
にいろいろログが表示されるようになる.