DevToolsを使ったJavaScriptのデバッグ 第1回 ブレークポイントの基本

ChromeのDevToolsを例に、ブレークポイントの使い方を解説します。プログラムの任意の行を基準に、処理が進む過程をコントロールしながら、関数の実行や、変数の内容などを検証していくことができます。

発行

著者 菅野 亜実 フロントエンド・エンジニア
DevToolsを使ったJavaScriptのデバッグ シリーズの記事一覧

デバッグスキルを高める

プログラマに必要とされるスキルはいくつかありますが、その中でもエラーの原因をすばやく突き止めることができる、デバッグのスキルは非常に重要なスキルのひとつです。

デバッグのスキルは経験に依存するところも大きいですが、ツールの使い方を知り、使いこなせることも重要です。

本シリーズでは、ChromeのDevToolsを利用したJavaScriptのデバッグ手法を解説します。

最初に取り上げるのは、ブレークポイントという機能です。この機能を使って途中でプログラムの実行を止めることで、効率的にデバッグする手法を紹介します。

console.logでのデバッグ

JavaScriptを普段書いている人であれば、console.logを使ったことがないという人はまずいないでしょう。

console.logを使うと、プログラム実行中の変数の状態を出力できたり、特定の行が実行されているかを確認できたりと、開発時には大変便利な機能です。

console.logで要素を取得する例

const $el = document.querySelector('.foo');

console.log($el); // 要素が取得できているか確認

console.logだけでもある程度のケースはカバーできますが、今回紹介するブレークポイントを使うと、console.logだけではデバッグが難しいケースでも、効率よくデバッグすることができるようになります。

ブレークポイントの設定

ブレークポイントは、プログラムの実行を任意の場所で一時停止する機能です。停止した場所の変数の状態やコールスタック(関数の呼び出し経路)を確認したり、停止した場所からコードの実行を一つ一つ自分で進めることができます。

次の例を元にブレークポイントの使い方を解説していきます。

解説に利用するコード

function sum(arr) {
  const _sum = arr.reduce((a, b) => {
    return a + b
  })

  return _sum
}

function average(arr) {
  const _sum = sum(arr)
  const _avg = _sum / arr.length

  return _avg
}

const avg = average([1, 2, 3, 4, 5])
console.log(avg)

配列で渡した数値の合計を返すsum関数*と、平均値を返すaverage関数があり、average関数は内部でsum関数を利用しています。

*注:sum関数の実装

sum関数では、配列のreduceメソッドを使って、全要素の合計値を求めています。reduceメソッドについては、次の記事も合わせて読むことで理解が深まるでしょう。

ここで、average関数を実行したときの動作をブレークポイントを使って追いかけてみます。

次のサンプルで、[新規タブで開く]をクリックして、別タブで表示してください。

そして、DevToolsの[ソース]タブを開き、左上の[ナビゲータを表示]ボタンをクリックすると、左側にファイルの一覧が表示されます。

表示されたファイルの一覧の中から、デバッグしたいソース(app.js)を選択することで、ソースコードを見ながらデバッグすることができます。

このように、[ソース]タブでブレークポイントを設定したいファイルを開いたら、左側の行番号が書いてある部分をクリックすることで、ブレークポイントを設定することができます。

まずはaverageの最初の行(10行目)をクリックします。

すると、左側に青い矢印のようなマークがつきます。これがブレークポイントを設定した状態です。

この状態でリロードすると10行目で処理が止まり、次のような状態になります。

この状態では、JavaScriptの処理が黄色い背景の行の前で完全にストップした状態になります。たとえば、ブラウザのスクロールなども動きませんし、ページの読込中であれば、このスクリプト以降のHTMLのレンダリングも行われず、ブラウザのページのタブには、読込中のクルクルが出たままの状態になります。

処理を進める

ブレークポイントを設定した行の直前で処理が止まった状態から、手動で処理を進めることで、デバッグを行っていきます。

処理を進めるには、右上にあるいくつか矢印のボタンを使います。

これらは左から順に、次のような役割を持つボタンです。

  • 処理の再開/停止
  • ステップオーバー
  • ステップイン
  • ステップアウト
  • ステップ
  • ブレークポイントの有効/無効の切り替え

特に重要なのは、ステップオーバー、ステップイン、ステップアウトの3つのボタンです。それぞれについてどのような動作なのかを解説します。

ステップオーバー

ステップオーバーは、現在の行を実行し、次の行に処理を進める基本的な操作です。もし現在の行に関数呼び出しがあったとしても、呼び出された関数内部へはジャンプせずに関数を実行し、次の行に進みます。

ただし、次の行に進むだけで、その行が実行されるわけではありません。

前述の例では、average関数の最初の行(10行目)にブレークポイントを設定していました。この状態でステップオーバーを行うと、次のようになります。

sum関数が実行されていますが、sum関数内部にはジャンプせず、次の行に進んでいることがわかります。

ここで、9行目にはarr = (5) [1, 2, 3, 4, 5]という表示が、10行目には_sum = 15というインライン表示が追加されています。

薄い赤色の背景付きのこれらの表示は、関数に渡された引数の値や、変数の現在の値を示すものです。

このように、処理を進めていくごとに値のインライン表示が追加されていくため、意図しない値の変化が起きていないかどうか、1行ずつ確かめながらデバッグすることができます。

ステップイン

ステップインも、現在の行を実行し、次の行に進める操作です。ステップオーバーとは異なり、呼び出された関数内部の処理も一つ一つ追いかけることができます。

ステップインでは、もし現在の行に関数呼び出しがあった場合、その関数の定義箇所にジャンプし、関数の内部に処理を進めます。

average関数の最初の行(10行目)でステップインを行うと次のようになります。

今度はsum関数の内部にジャンプしたことがわかります。

この状態で再度ステップインを行うと、さらにreduceメソッドの引数として指定した関数の内部にジャンプします。

reduceメソッドによって繰り返し呼び出される関数は、abという2つの引数を持ちますが、これらの現在の値a = 1, b = 2が2行目にインライン表示されていることに注目してください。

続けてステップインを実行していくことで、引数の値の変化をインライン表示で確認しながらデバッグすることができます。

このように、ステップインは関数内部の処理のデバッグに役立ちます。

なお、関数呼び出しがない行では、ステップオーバーとステップインはどちらを押しても同じ結果になります。

ステップアウト

関数内部から脱出し、関数呼び出し後の処理に進むには、ステップアウトを使います。

ステップアウトでは、現在の行の呼び出し元の関数が終了するまで実行し、関数を抜けます。

average関数の最初の行(10行目)でステップアウトを行うと次のようになります。

average関数を呼び出していた16行目の処理が終わった状態になり、17行目にジャンプしたことがわかります。

このように、ステップオーバー、ステップイン、ステップアウトをうまく使うことで、処理を進めていくのが基本的な使い方です。

ソースコード中でブレークポイントを設定する

本記事ではDevToolsからブレークポイントを設定しましたが、この方法のほかに、JavaScriptのソースコードの中でブレークポイントを指定する方法もあります。

ブレークポイントを設定したい行の前にdebugger文を書いておくことで、DevToolsからブレークポイントを設定したときと同じ動作になります。

ソースコードの中にブレークポイントを設定した場合

function average(arr) {
  debugger;
  const _sum = sum(arr);
  const _avg = _sum / arr.length;

  return _avg;
}

ただし、ユーザーが利用する環境にdebugger文が残ってしまうと、ユーザーの利用中に処理が止まってしまうので注意が必要です。

まとめ

今回は、ChromeのDevToolsを使って、JavaScriptのコードにブレークポイントを設定し、そこから処理を進めていく基本的な操作を解説しました。

ChromeのDevtoolsには、ブレークポイントで処理を進めていく中で、合わせて活用すると便利な機能があります。変数の値を変えながら検証したり、関数がどのような順番で呼び出されるかを確認したり、といった機能です。

次回は、これらの機能も合わせて、ブレークポイントを活用していきましょう。