序章

Node.js開発では、コーディングエラーをソースまでさかのぼって追跡することで、プロジェクトの過程で多くの時間を節約できます。 しかし、プログラムの複雑さが増すにつれて、これを効率的に行うことはますます難しくなります。 この問題を解決するために、開発者はデバッガーのようなツールを使用します。これは、開発者が実行中にプログラムを検査できるようにするプログラムです。 コードを1行ずつ再生し、プログラムの状態がどのように変化するかを観察することで、デバッガーはプログラムの実行状況を洞察し、バグを見つけやすくします。

プログラマーがコードのバグを追跡するために使用する一般的な方法は、プログラムの実行時にステートメントを印刷することです。 Node.jsでは、モジュールに console.log()またはconsole.debug()ステートメントを追加する必要があります。 この手法はすばやく使用できますが、手動でもあるため、拡張性が低くなり、エラーが発生しやすくなります。 この方法を使用すると、機密情報を誤ってコンソールに記録する可能性があり、悪意のあるエージェントに顧客またはアプリケーションに関する個人情報を提供する可能性があります。 一方、デバッガーは、プログラムをセキュリティの脅威にさらすことなく、プログラムで何が起こっているかを体系的に監視する方法を提供します。

デバッガーの主な機能は、監視オブジェクトとブレークポイントの追加です。 オブジェクトを監視することにより、デバッガーは、プログラマーがプログラムをステップ実行するときに変数の変更を追跡するのに役立ちます。 ブレークポイントは、開発者が調査しているポイントを超えてコードが続行されないようにするために、プログラマーがコードに配置できるマーカーです。

この記事では、デバッガーを使用して、いくつかのサンプルNode.jsアプリケーションをデバッグします。 まず、組み込みの Node.jsデバッガツールを使用してコードをデバッグし、バグの根本原因を見つけることができるようにウォッチャーとブレークポイントを設定します。 次に、コマンドラインNode.jsデバッガーの代わりに Google Chrome DevTools グラフィカルユーザーインターフェイス(GUI)として使用します。

前提条件

  • 開発環境にNode.jsをインストールする必要があります。 このチュートリアルでは、バージョン10.19.0を使用します。 これをmacOSまたはUbuntu18.04にインストールするには、Node.jsをインストールしてmacOSにローカル開発環境を作成する方法またはPPAを使用したインストール]セクションの手順に従います。 Ubuntu18.04にNode.jsをインストールする方法。
  • この記事では、ユーザーが基本的なJavaScript、特に関数の作成と使用に慣れていることを期待しています。 JavaScriptシリーズのコーディング方法を読むことで、これらの基礎などを学ぶことができます。
  • Chrome DevToolsデバッガーを使用するには、 GoogleChromeWebブラウザーまたはオープンソースのChromiumWebブラウザーをダウンロードしてインストールする必要があります。

ステップ1—Node.jsデバッガーでウォッチャーを使用する

デバッガーは主に2つの機能に役立ちます。変数を監視し、プログラムの実行時に変数がどのように変化するかを観察する機能と、ブレークポイントと呼ばれるさまざまな場所でコードの実行を停止および開始する機能です。 このステップでは、変数を監視してコードのエラーを特定する方法を実行します。

コードをステップ実行するときに変数を監視することで、プログラムの実行中に変数の値がどのように変化するかを知ることができます。 例を使用して、コード内の論理エラーを見つけて修正するのに役立つ変数の監視を練習しましょう。

まず、コーディング環境を設定します。 ターミナルで、という名前の新しいフォルダを作成します debugging:

  1. mkdir debugging

次に、そのフォルダに入ります。

  1. cd debugging

と呼ばれる新しいファイルを開きます badLoop.js. 我々は使用するだろう nano ターミナルで利用できるように:

  1. nano badLoop.js

このコードは、 array を反復処理し、合計に数値を加算します。この例では、店舗での1週間の1日の注文数を加算するために使用されます。 プログラムは、配列内のすべての数値の合計を返します。 エディターで、次のコードを入力します。

デバッグ/badLoop.js
let orders = [341, 454, 198, 264, 307];

let totalOrders = 0;

for (let i = 0; i <= orders.length; i++) {
  totalOrders += orders[i];
}

console.log(totalOrders);

まず、 orders 5つの数値を格納する配列。 次に初期化します totalOrders0、5つの数値の合計を格納するため。 forループでは、各値を繰り返し加算します。 orderstotalOrders. 最後に、プログラムの最後に注文の合計金額を印刷します。

保存してエディターを終了します。 今、このプログラムを実行します node:

  1. node badLoop.js

端末に次の出力が表示されます。

Output
NaN

JavaScriptのNaNは、数値ではないを意味します。 すべての入力が有効な数値であることを考えると、これは予期しない動作です。 エラーを見つけるために、Node.jsデバッガーを使用して、で変更された2つの変数がどうなるかを確認しましょう。 for ループ: totalOrdersi.

プログラムで組み込みのNode.jsデバッガーを使用する場合は、次のものを含めます。 inspect ファイル名の前。 ターミナルで、 node 次のように、このデバッガオプションを指定してコマンドを実行します。

  1. node inspect badLoop.js

デバッガーを起動すると、次のような出力が表示されます。

Output
< Debugger listening on ws://127.0.0.1:9229/e1ebba25-04b8-410b-811e-8a0c0902717a < For help, see: https://nodejs.org/en/docs/inspector < Debugger attached. Break on start in badLoop.js:1 > 1 let orders = [341, 454, 198, 264, 307]; 2 3 let totalOrders = 0;

最初の行は、デバッグサーバーのURLを示しています。 これは、後で説明するWebブラウザなどの外部クライアントでデバッグする場合に使用されます。 このサーバーはポートでリッスンすることに注意してください :9229localhost (127.0.0.1)デフォルトで。 セキュリティ上の理由から、このポートを一般に公開しないことをお勧めします。

デバッガーが接続された後、デバッガーは出力します Break on start in badLoop.js:1.

ブレークポイントは、実行を停止するコード内の場所です。 デフォルトでは、Node.jsのデバッガーはファイルの先頭で実行を停止します。

次に、デバッガーはコードのスニペットを表示し、その後に特別なコードが続きます debug 促す:

Output
... > 1 let orders = [341, 454, 198, 264, 307]; 2 3 let totalOrders = 0; debug>

The > の隣に 1 実行で到達した行を示します。プロンプトは、デバッガーへの表彰を入力する場所です。 この出力が表示されると、デバッガーはコマンドを受け入れる準備ができています。

デバッガーを使用する場合、プログラムが実行する次の行に移動するようにデバッガーに指示することにより、コードをステップスルーします。 Node.jsでは、次のコマンドでデバッガーを使用できます。

  • c また cont:次のブレークポイントまたはプログラムの最後まで実行を続行します。
  • n また next:コードの次の行に移動します。
  • s また step:関数にステップインします。 デフォルトでは、デバッグしているブロックまたはscopeのコードのみをステップスルーします。 関数にステップインすることで、コードが呼び出す関数のコードを検査し、それがデータにどのように反応するかを観察できます。
  • o:関数からステップアウトします。 関数にステップインした後、関数が戻ると、デバッガーはメインファイルに戻ります。 このコマンドを使用して、関数の実行が完了する前にデバッグしていた元の関数に戻ることができます。
  • pause:実行中のコードを一時停止します。

このコードを1行ずつ説明します。 プレス n 次の行に移動するには:

  1. n

これで、デバッガーはコードの3行目でスタックします。

Output
break in badLoop.js:3 1 let orders = [341, 454, 198, 264, 307]; 2 > 3 let totalOrders = 0; 4 5 for (let i = 0; i <= orders.length; i++) {

便宜上、空の行はスキップされます。 押すと n もう一度デバッグコンソールで、デバッガーはコードの5行目に配置されます。

Output
break in badLoop.js:5 3 let totalOrders = 0; 4 > 5 for (let i = 0; i <= orders.length; i++) { 6 totalOrders += orders[i]; 7 }

現在、ループを開始しています。 端末がカラーをサポートしている場合、 0let i = 0 強調表示されます。 デバッガーは、プログラムが実行しようとしているコードの部分を強調表示します。 for ループでは、カウンタの初期化が最初に実行されます。 ここから、理由を確認できます totalOrders 戻ってきました NaN 数字の代わりに。 このループでは、反復ごとに2つの変数が変更されます—totalOrdersi. これらの変数の両方にウォッチャーを設定しましょう。

まず、ウォッチャーを追加します totalOrders 変数。 インタラクティブシェルで、次のように入力します。

  1. watch('totalOrders')

変数を監視するには、組み込みのを使用します watch() 変数名を含むstring引数を持つ関数。 押すと ENTERwatch() 関数の場合、プロンプトはフィードバックを提供せずに次の行に移動しますが、デバッガーを次の行に移動するとウォッチワードが表示されます。

次に、変数のウォッチャーを追加しましょう i:

  1. watch('i')

これで、ウォッチャーの動作を確認できます。 プレス n 次のステップに進みます。 デバッグコンソールには次のように表示されます。

Output
break in badLoop.js:5 Watchers: 0: totalOrders = 0 1: i = 0 3 let totalOrders = 0; 4 > 5 for (let i = 0; i <= orders.length; i++) { 6 totalOrders += orders[i]; 7 }

デバッガーは次の値を表示します totalOrdersi 出力に示されているように、コード行を表示する前に。 これらの値は、コード行によって変更されるたびに更新されます。

この時点で、デバッガーは強調表示されています lengthorders.length. これは、プログラムがブロック内のコードを実行する前に、条件をチェックしようとしていることを意味します。 コードが実行された後、最終的な式 i++ 実行されます。 あなたはについてもっと読むことができます for JavaScriptガイドでForループを作成する方法のループとその実行。

入る n コンソールで入力するには for ループの本体:

Output
break in badLoop.js:6 Watchers: 0: totalOrders = 0 1: i = 0 4 5 for (let i = 0; i <= orders.length; i++) { > 6 totalOrders += orders[i]; 7 } 8

このステップは、 totalOrders 変数。 したがって、このステップが完了すると、変数とウォッチャーが更新されます。

プレス n 確認するために。 あなたはこれを見るでしょう:

Output
Watchers: 0: totalOrders = 341 1: i = 0 3 let totalOrders = 0; 4 > 5 for (let i = 0; i <= orders.length; i++) { 6 totalOrders += orders[i]; 7 }

強調表示されているように。 totalOrders これで、1次の値が得られます。 341.

デバッガーは、ループの最終条件を処理しようとしています。 入る n したがって、この行を実行して更新します i:

Output
break in badLoop.js:5 Watchers: 0: totalOrders = 341 1: i = 1 3 let totalOrders = 0; 4 > 5 for (let i = 0; i <= orders.length; i++) { 6 totalOrders += orders[i]; 7 }

初期化後、変数が更新されるのを確認するために、コードを4回ステップ実行する必要がありました。 このようにコードをステップ実行するのは面倒な場合があります。 この問題は、ステップ2のブレークポイントで対処されます。 しかし今のところ、ウォッチャーを設定することで、ウォッチャーの価値を観察し、問題を見つける準備ができています。

次のように入力して、プログラムをステップスルーします n 出力を観察しながら、さらに12回。 コンソールには次のように表示されます。

Output
break in badLoop.js:5 Watchers: 0: totalOrders = 1564 1: i = 5 3 let totalOrders = 0; 4 > 5 for (let i = 0; i <= orders.length; i++) { 6 totalOrders += orders[i]; 7 }

私たちのことを思い出してください orders 配列には5つの項目があり、 i 現在の位置にあります 5. しかしそれ以来 i 配列のインデックスとして使用され、に値はありません orders[5]; の最後の値 orders 配列はインデックスにあります 4. この意味は orders[5] の値は undefined.

タイプ n コンソールで、ループ内のコードが実行されていることを確認します。

Output
break in badLoop.js:6 Watchers: 0: totalOrders = 1564 1: i = 5 4 5 for (let i = 0; i <= orders.length; i++) { > 6 totalOrders += orders[i]; 7 } 8

タイピング n もう一度の値を示しています totalOrders その反復の後:

Output
break in badLoop.js:5 Watchers: 0: totalOrders = NaN 1: i = 5 3 let totalOrders = 0; 4 > 5 for (let i = 0; i <= orders.length; i++) { 6 totalOrders += orders[i]; 7 }

デバッグと監視を通じて totalOrdersi、ループが5回ではなく6回繰り返されていることがわかります。 いつ i5, orders[5] に追加されます totalOrders. 以来 orders[5]undefined、これを数値に追加すると、 NaN. したがって、コードの問題は私たちの中にあります for ループの状態。 チェックする代わりに i の長さ以下 orders 配列の場合、長さよりも短いことだけを確認する必要があります。

デバッガーを終了し、変更を加えて、コードを再実行しましょう。 デバッグプロンプトで、exitコマンドを入力し、を押します。 ENTER:

  1. .exit

デバッガーを終了したので、を開きます badLoop.js テキストエディタで:

  1. nano badLoop.js

変更 for ループの状態:

デバッガー/badLoop.js
...
for (let i = 0; i < orders.length; i++) {
...

保存して終了 nano. 次に、次のようにスクリプトを実行してみましょう。

  1. node badLoop.js

完了すると、正しい結果が出力されます。

Output
1564

このセクションでは、デバッガーを使用しました watch コードのバグを見つけて修正し、期待どおりに機能することを確認するコマンド。

デバッガーを使用して変数を監視する基本的な経験ができたので、プログラムの最初からすべてのコード行をステップ実行せずにデバッグできるように、ブレークポイントを使用する方法を見てみましょう。

ステップ2—Node.jsデバッガーでブレークポイントを使用する

Node.jsプロジェクトは、相互接続された多くのモジュールで構成されるのが一般的です。 特にアプリの複雑さが増すにつれて、各モジュールを1行ずつデバッグするのは時間がかかります。 この問題を解決するために、ブレークポイントを使用すると、実行を一時停止してプログラムを検査するコード行にジャンプできます。

Node.jsでデバッグする場合、ブレークポイントを追加して debugger 私たちのコードに直接キーワード。 次に、を押して、あるブレークポイントから次のブレークポイントに移動できます。 c 代わりにデバッガコンソールで n. 各ブレークポイントで、関心のある表現のウォッチャーを設定できます。

これを例で見てみましょう。 このステップでは、文のリストを読み取り、すべてのテキストで使用される最も一般的な単語を判別するプログラムをセットアップします。 サンプルコードは、出現回数が最も多い最初の単語を返します。

この演習では、3つのファイルを作成します。 最初のファイル、 sentences.txt、プログラムが処理する生データが含まれます。 Encyclopaedia Britannicaのジンベイザメに関する記事の冒頭のテキストを、句読点を削除してサンプルデータとして追加します。

テキストエディタでファイルを開きます。

  1. nano sentences.txt

次に、次のコードを入力します。

デバッガー/sentences.txt
Whale shark Rhincodon typus gigantic but harmless shark family Rhincodontidae that is the largest living fish
Whale sharks are found in marine environments worldwide but mainly in tropical oceans
They make up the only species of the genus Rhincodon and are classified within the order Orectolobiformes a group containing the carpet sharks
The whale shark is enormous and reportedly capable of reaching a maximum length of about 18 metres 59 feet
Most specimens that have been studied however weighed about 15 tons about 14 metric tons and averaged about 12 metres 39 feet in length
The body coloration is distinctive
Light vertical and horizontal stripes form a checkerboard pattern on a dark background and light spots mark the fins and dark areas of the body

ファイルを保存して終了します。

それでは、コードをに追加しましょう textHelper.js. このモジュールには、テキストファイルの処理に使用するいくつかの便利な関数が含まれているため、最も人気のある単語を簡単に判別できます。 開ける textHelper.js テキストエディタで:

  1. nano textHelper.js

データを処理するための3つの関数を作成します sentences.txt. 1つ目は、ファイルを読み取ることです。 次のように入力します textHelper.js:

デバッガー/textHelper.js
const fs = require('fs');

const readFile = () => {
  let data = fs.readFileSync('sentences.txt');
  let sentences = data.toString();
  return sentences;
};

まず、 fs Node.jsライブラリをインポートして、ファイルを読み取れるようにします。 次に、 readFile() を使用する関数 readFileSync() からデータをロードするには sentences.txt バッファオブジェクトおよび toString() 文字列として返すメソッド。

追加する次の関数は、テキストの文字列を処理し、その単語を含む配列にフラット化します。 次のコードをエディターに追加します。

textHelper.js
...

const getWords = (text) => {
  let allSentences = text.split('\n');
  let flatSentence = allSentences.join(' ');
  let words = flatSentence.split(' ');
  words = words.map((word) => word.trim().toLowerCase());
  return words;
};

このコードでは、メソッド split() join()、および map()を使用して、文字列を個々の単語の配列に操作しています。 また、この関数は、カウントを容易にするために各単語を小文字にします。

必要な最後の関数は、文字列配列内のさまざまな単語の数を返します。 次のような最後の関数を追加します。

デバッガー/textHelper.js
...

const countWords = (words) => {
  let map = {};
  words.forEach((word) => {
    if (word in map) {
      map[word] = 1;
    } else {
      map[word] += 1;
    }
  });

  return map;
};

ここでは、JavaScriptオブジェクトを作成します。 map キーとして単語があり、値としてカウントされます。 配列をループし、ループの現在の要素である場合は、各単語の数に1を追加します。 これらの関数をエクスポートして、他のモジュールで使用できるようにして、このモジュールを完成させましょう。

デバッガー/textHelper.js
...

module.exports = { readFile, getWords, countWords };

保存して終了。

この演習で使用する3番目の最後のファイルでは、 textHelper.js 私たちのテキストで最も人気のある単語を見つけるためのモジュール。 開ける index.js テキストエディタで:

  1. nano index.js

コードをインポートすることから始めます textHelpers.js モジュール:

デバッガー/index.js
const textHelper = require('./textHelper');

ストップワードを含む新しいアレイを作成して続行します。

デバッガー/index.js
...

const stopwords = ['i', 'me', 'my', 'myself', 'we', 'our', 'ours', 'ourselves', 'you', 'your', 'yours', 'yourself', 'yourselves', 'he', 'him', 'his', 'himself', 'she', 'her', 'hers', 'herself', 'it', 'its', 'itself', 'they', 'them', 'their', 'theirs', 'themselves', 'what', 'which', 'who', 'whom', 'this', 'that', 'these', 'those', 'am', 'is', 'are', 'was', 'were', 'be', 'been', 'being', 'have', 'has', 'had', 'having', 'do', 'does', 'did', 'doing', 'a', 'an', 'the', 'and', 'but', 'if', 'or', 'because', 'as', 'until', 'while', 'of', 'at', 'by', 'for', 'with', 'about', 'against', 'between', 'into', 'through', 'during', 'before', 'after', 'above', 'below', 'to', 'from', 'up', 'down', 'in', 'out', 'on', 'off', 'over', 'under', 'again', 'further', 'then', 'once', 'here', 'there', 'when', 'where', 'why', 'how', 'all', 'any', 'both', 'each', 'few', 'more', 'most', 'other', 'some', 'such', 'no', 'nor', 'not', 'only', 'own', 'same', 'so', 'than', 'too', 'very', 's', 't', 'can', 'will', 'just', 'don', 'should', 'now', ''];

ストップワードは、テキストを処理する前に除外する言語で一般的に使用される単語です。 これを使用して、英語のテキストで最も人気のある単語が the また a.

を使用して続行します textHelper.js 単語とその数を含むJavaScriptオブジェクトを取得するモジュール関数:

デバッガー/index.js
...

let sentences = textHelper.readFile();
let words = textHelper.getWords(sentences);
let wordCounts = textHelper.countWords(words);

次に、最も頻度の高い単語を判別することにより、このモジュールを完了できます。 これを行うには、オブジェクトの各キーを単語数でループし、その数を以前に保存された最大値と比較します。 単語の数が多い場合は、新しい最大値になります。

次のコード行を追加して、最も人気のある単語を計算します。

デバッガー/index.js
...

let max = -Infinity;
let mostPopular = '';

Object.entries(wordCounts).forEach(([word, count]) => {
  if (stopwords.indexOf(word) === -1) {
    if (count > max) {
      max = count;
      mostPopular = word;
    }
  }
});

console.log(`The most popular word in the text is "${mostPopular}" with ${max} occurrences`);

このコードでは、 Object.entries()を使用して、 wordCounts オブジェクトを個々の配列に分割します。これらはすべて、より大きな配列内にネストされています。 次に、 forEach()メソッドといくつかの条件付きステートメントを使用して、各単語の数をテストし、最大数を格納します。

ファイルを保存して終了します。

このファイルを実行して、実際の動作を確認してみましょう。 端末で次のコマンドを入力します。

  1. node index.js

次の出力が表示されます。

Output
The most popular word in the text is "whale" with 1 occurrences

テキストを読むと、答えが間違っていることがわかります。 でのクイック検索 sentences.txt その単語を強調します whale 複数回表示されます。

このエラーを引き起こす可能性のある関数がかなりあります。ファイル全体を読み取っていないか、テキストを配列とJavaScriptオブジェクトに正しく処理していない可能性があります。 最大の単語を見つけるためのアルゴリズムも正しくない可能性があります。 何が悪いのかを理解する最良の方法は、デバッガーを使用することです。

大規模なコードベースがなくても、コードの各行をステップスルーして、状況がいつ変化するかを観察することに時間を費やしたくありません。 代わりに、ブレークポイントを使用して、関数が戻る前にそれらの重要な瞬間に移動し、出力を観察できます。

の各関数にブレークポイントを追加しましょう textHelper.js モジュール。 そのためには、キーワードを追加する必要があります debugger 私たちのコードに。

を開きます textHelper.js テキストエディタのファイル。 使用します nano もう一度:

  1. nano textHelper.js

まず、ブレークポイントをに追加します readFile() このように機能します:

デバッガー/textHelper.js
...

const readFile = () => {
  let data = fs.readFileSync('sentences.txt');
  let sentences = data.toString();
  debugger;
  return sentences;
};

...

次に、別のブレークポイントをに追加します getWords() 関数:

デバッガー/textHelper.js
...

const getWords = (text) => {
  let allSentences = text.split('\n');
  let flatSentence = allSentences.join(' ');
  let words = flatSentence.split(' ');
  words = words.map((word) => word.trim().toLowerCase());
  debugger;
  return words;
};

...

最後に、ブレークポイントを追加します countWords() 関数:

デバッガー/textHelper.js
...

const countWords = (words) => {
  let map = {};
  words.forEach((word) => {
    if (word in map) {
      map[word] = 1;
    } else {
      map[word] += 1;
    }
  });

  debugger;
  return map;
};

...

保存して終了 textHelper.js.

デバッグプロセスを始めましょう。 ブレークポイントはありますが textHelpers.js、アプリケーションのエントリのメインポイントをデバッグしています。 index.js. シェルで次のコマンドを入力して、デバッグセッションを開始します。

  1. node inspect index.js

コマンドを入力すると、次の出力が表示されます。

Output
< Debugger listening on ws://127.0.0.1:9229/b2d3ce0e-3a64-4836-bdbf-84b6083d6d30 < For help, see: https://nodejs.org/en/docs/inspector < Debugger attached. Break on start in index.js:1 > 1 const textHelper = require('./textHelper'); 2 3 const stopwords = ['i', 'me', 'my', 'myself', 'we', 'our', 'ours', 'ourselves', 'you', 'your', 'yours', 'yourself', 'yourselves', 'he', 'him', 'his', 'himself', 'she', 'her', 'hers', 'herself', 'it', 'its', 'itself', 'they', 'them', 'their', 'theirs', 'themselves', 'what', 'which', 'who', 'whom', 'this', 'that', 'these', 'those', 'am', 'is', 'are', 'was', 'were', 'be', 'been', 'being', 'have', 'has', 'had', 'having', 'do', 'does', 'did', 'doing', 'a', 'an', 'the', 'and', 'but', 'if', 'or', 'because', 'as', 'until', 'while', 'of', 'at', 'by', 'for', 'with', 'about', 'against', 'between', 'into', 'through', 'during', 'before', 'after', 'above', 'below', 'to', 'from', 'up', 'down', 'in', 'out', 'on', 'off', 'over', 'under', 'again', 'further', 'then', 'once', 'here', 'there', 'when', 'where', 'why', 'how', 'all', 'any', 'both', 'each', 'few', 'more', 'most', 'other', 'some', 'such', 'no', 'nor', 'not', 'only', 'own', 'same', 'so', 'than', 'too', 'very', 's', 't', 'can', 'will', 'just', 'don', 'should', 'now', ''];

今回は、 c インタラクティブデバッガに。 念のため、 c 継続の略です。 これにより、デバッガーがコード内の次のブレークポイントにジャンプします。 押した後 c とタイピング ENTER、コンソールにこれが表示されます。

Output
break in textHelper.js:6 4 let data = fs.readFileSync('sentences.txt'); 5 let sentences = data.toString(); > 6 debugger; 7 return sentences; 8 };

ブレークポイントに直接移動することで、デバッグ時間を節約できました。

この関数では、ファイル内のすべてのテキストが返されることを確認する必要があります。 のウォッチャーを追加します sentences 何が返されるかを確認できるように変数:

  1. watch('sentences')

プレス n コードの次の行に移動して、内容を確認できるようにします sentences. 次の出力が表示されます。

Output
break in textHelper.js:7 Watchers: 0: sentences = 'Whale shark Rhincodon typus gigantic but harmless shark family Rhincodontidae that is the largest living fish\n' + 'Whale sharks are found in marine environments worldwide but mainly in tropical oceans\n' + 'They make up the only species of the genus Rhincodon and are classified within the order Orectolobiformes a group containing the carpet sharks\n' + 'The whale shark is enormous and reportedly capable of reaching a maximum length of about 18 metres 59 feet\n' + 'Most specimens that have been studied however weighed about 15 tons about 14 metric tons and averaged about 12 metres 39 feet in length\n' + 'The body coloration is distinctive\n' + 'Light vertical and horizontal stripes form a checkerboard pattern on a dark background and light spots mark the fins and dark areas of the body\n' 5 let sentences = data.toString(); 6 debugger; > 7 return sentences; 8 }; 9

ファイルの読み取りに問題はないようです。 問題はコードの他の場所にあるはずです。 を押して次のブレークポイントに移動しましょう c もう一度。 実行すると、次の出力が表示されます。

Output
break in textHelper.js:15 Watchers: 0: sentences = ReferenceError: sentences is not defined at eval (eval at getWords (your_file_path/debugger/textHelper.js:15:3), <anonymous>:1:1) at Object.getWords (your_file_path/debugger/textHelper.js:15:3) at Object.<anonymous> (your_file_path/debugger/index.js:7:24) at Module._compile (internal/modules/cjs/loader.js:1125:14) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1167:10) at Module.load (internal/modules/cjs/loader.js:983:32) at Function.Module._load (internal/modules/cjs/loader.js:891:14) at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12) at internal/main/run_main_module.js:17:47 13 let words = flatSentence.split(' '); 14 words = words.map((word) => word.trim().toLowerCase()); >15 debugger; 16 return words; 17 };

ウォッチャーを設定したため、このエラーメッセージが表示されます。 sentences 変数ですが、その変数は現在の関数スコープに存在しません。 ウォッチャーは、私たちが監視し続ける限り、デバッグセッション全体にわたって持続します sentences 定義されていない場合は、引き続きこのエラーが表示されます。

変数の監視を停止できます unwatch() 指図。 見ないようにしましょう sentences そのため、デバッガーが出力を出力するたびにこのエラーメッセージを表示する必要がなくなりました。 対話型プロンプトで、次のコマンドを入力します。

  1. unwatch('sentences')

変数の監視を解除しても、デバッガーは何も出力しません。

に戻る getWords() 関数では、前にロードしたテキストから取得した単語のリストを確実に返す必要があります。 の価値を見てみましょう words 変数:

  1. watch('words')

次に入力します n デバッガーの次の行に移動して、何が格納されているかを確認できるようにします words. デバッガーは次のように表示します。

Output
break in textHelper.js:16 Watchers: 0: words = [ 'whale', 'shark', 'rhincodon', 'typus', 'gigantic', 'but', 'harmless', ... 'metres', '39', 'feet', 'in', 'length', '', 'the', 'body', 'coloration', ... ] 14 words = words.map((word) => word.trim().toLowerCase()); 15 debugger; >16 return words; 17 }; 18

デバッガーは配列全体を出力しません。これは非常に長く、出力が読みにくくなるためです。 ただし、出力は、何を保存する必要があるかという私たちの期待を満たしています。 sentences 小文字の文字列に分割します。 のようだ getWords() 正しく機能しています。

観察に移りましょう countWords() 関数。 まず、見ないでください words 配列なので、次のブレークポイントにいるときにデバッガーエラーが発生しません。 コマンドプロンプトで、次のように入力します。

  1. unwatch('words')

次に、 c プロンプトで。 最後のブレークポイントで、これがシェルに表示されます。

Output
break in textHelper.js:29 27 }); 28 >29 debugger; 30 return map; 31 };

この関数では、 map 変数には、文の各単語の数が正しく含まれています。 まず、デバッガーに監視するように指示しましょう。 map 変数:

  1. watch('map')

プレス n 次の行に移動します。 デバッガーはこれを表示します:

Output
break in textHelper.js:30 Watchers: 0: map = { 12: NaN, 14: NaN, 15: NaN, 18: NaN, 39: NaN, 59: NaN, whale: 1, shark: 1, rhincodon: 1, typus: NaN, gigantic: NaN, ... } 28 29 debugger; >30 return map; 31 }; 32

それは正しく見えません。 単語を数える方法が間違った結果を生み出しているようです。 これらの値が入力されている理由がわからないため、次のステップは、で使用されるループで何が起こっているかをデバッグすることです。 words 配列。 これを行うには、ブレークポイントを配置する場所にいくつかの変更を加える必要があります。

まず、デバッグコンソールを終了します。

  1. .exit

開ける textHelper.js テキストエディタでブレークポイントを編集できるようにします。

  1. nano textHelper.js

まず、それを知っている readFile()getWords() 動作している場合は、ブレークポイントを削除します。 次に、ブレークポイントを削除します countWords() 関数の最後から、2つの新しいブレークポイントを最初と最後に追加します。 forEach() ブロック。

編集 textHelper.js したがって、次のようになります。

デバッガー/textHelper.js
...

const readFile = () => {
  let data = fs.readFileSync('sentences.txt');
  let sentences = data.toString();
  return sentences;
};

const getWords = (text) => {
  let allSentences = text.split('\n');
  let flatSentence = allSentences.join(' ');
  let words = flatSentence.split(' ');
  words = words.map((word) => word.trim().toLowerCase());
  return words;
};

const countWords = (words) => {
  let map = {};
  words.forEach((word) => {
    debugger;
    if (word in map) {
      map[word] = 1;
    } else {
      map[word] += 1;
    }
    debugger;
  });

  return map;
};

...

保存して終了 nanoCTRL+X.

次のコマンドを使用して、デバッガーを再起動してみましょう。

  1. node inspect index.js

何が起こっているのかを洞察するために、ループ内のいくつかのことをデバッグしたいと思います。 まず、ウォッチャーを設定しましょう word、で使用される引数 forEach() ループが現在調べている文字列を含むループ。 デバッグプロンプトで、次のように入力します。

  1. watch('word')

これまでのところ、変数のみを監視してきました。 しかし、時計は変数に限定されません。 コードで使用されている有効なJavaScript式を監視できます。

実際には、状態のウォッチャーを追加できます word in map、これは私たちが数を数える方法を決定します。 デバッグプロンプトで、次のウォッチャーを作成します。

  1. watch('word in map')

で変更されている値のウォッチャーも追加しましょう map 変数:

  1. watch('map[word]')

ウォッチャーは、コードでは使用されていないが、コードで評価できる式にすることもできます。 の長さのウォッチャーを追加して、これがどのように機能するかを見てみましょう。 word 変数:

  1. watch('word.length')

すべてのウォッチャーを設定したので、入力しましょう c デバッガプロンプトに追加して、ループの最初の要素がどのように countWords() 評価されます。 デバッガーは次の出力を出力します。

Output
break in textHelper.js:20 Watchers: 0: word = 'whale' 1: word in map = false 2: map[word] = undefined 3: word.length = 5 18 let map = {}; 19 words.forEach((word) => { >20 debugger; 21 if (word in map) { 22 map[word] = 1;

ループの最初の単語は whale. この時点で、 map オブジェクトにはキーがありません whale その空として。 それに続いて、見上げると whalemap、 我々が得る undefined. 最後に、の長さ whale5. これは問題のデバッグには役立ちませんが、デバッグ中にコードで評価できる式を監視できることを検証します。

プレス c ループの終わりまでに何が変更されたかをもう一度確認します。 デバッガーはこれを表示します:

Output
break in textHelper.js:26 Watchers: 0: word = 'whale' 1: word in map = true 2: map[word] = NaN 3: word.length = 5 24 map[word] += 1; 25 } >26 debugger; 27 }); 28

ループの終わりに、 word in map として今真実です map 変数には whale 鍵。 の値 map のために whale キーは NaN、これは私たちの問題を浮き彫りにします。 The if のステートメント countWords() 単語の数が新しい場合は1に設定し、すでに存在する場合は1を追加することを意味します。

犯人は if ステートメントの条件。 設定する必要があります map[word]1 の場合 word に見つかりません map. 現在、次の場合に1つ追加しています word 見つかった。 ループの開始時に、 map["whale"]undefined. JavaScriptでは、 undefined + 1 に評価します NaN-数字ではありません。

これに対する修正は、の状態を変更することです。 if からの声明 (word in map)(!(word in map))、を使用して ! オペレーターが word にありません map. でその変更を加えましょう countWords() 何が起こるかを確認する関数。

まず、デバッガーを終了します。

  1. .exit

今すぐ開きます textHelper.js テキストエディタでファイル:

  1. nano textHelper.js

を変更します countWords() 次のように機能します。

デバッガー/textHelper.js
...

const countWords = (words) => {
  let map = {};
  words.forEach((word) => {
    if (!(word in map)) {
      map[word] = 1;
    } else {
      map[word] += 1;
    }
  });

  return map;
};

...

エディターを保存して閉じます。

それでは、デバッガーなしでこのファイルを実行してみましょう。 ターミナルで、次のように入力します。

  1. node index.js

スクリプトは次の文を出力します。

Output
The most popular word in the text is "whale" with 3 occurrences

この出力は、以前に受け取ったものよりもはるかに可能性が高いようです。 デバッガーを使用して、問題の原因となった関数と発生しなかった関数を特定しました。

組み込みのCLIデバッガーを使用して2つの異なるNode.jsプログラムをデバッグしました。 これで、ブレークポイントを設定できるようになりました。 debugger キーワードを設定し、内部状態の変化を観察するためのさまざまなウォッチャーを作成します。 ただし、GUIアプリケーションからコードをより効果的にデバッグできる場合もあります。

次のセクションでは、GoogleChromeのDevToolsのデバッガーを使用します。 Node.jsでデバッガーを起動し、Google Chromeの専用のデバッグページに移動し、GUIを使用してブレークポイントとウォッチャーを設定します。

ステップ3—ChromeDevToolsを使用したNode.jsのデバッグ

Chrome DevToolsは、WebブラウザーでNode.jsをデバッグするための一般的な選択肢です。 Node.jsはChromeが使用するのと同じV8JavaScriptエンジンを使用するため、デバッグエクスペリエンスは他のデバッガーよりも統合されています。

この演習では、HTTPサーバーを実行してJSON応答を返す新しいNode.jsアプリケーションを作成します。 次に、デバッガーを使用してブレークポイントを設定し、要求に対して生成されている応答についてより深い洞察を得ます。

という新しいファイルを作成しましょう server.js サーバーコードが保存されます。 テキストエディタでファイルを開きます。

  1. nano server.js

このアプリケーションは、JSONを返します Hello World 挨拶。 さまざまな言語のメッセージの配列があります。 リクエストを受信すると、ランダムに挨拶を選び、JSON本文で返します。

このアプリケーションは、 localhost ポート上のサーバー :8000. Node.jsを使用したHTTPサーバーの作成について詳しく知りたい場合は、 HTTPModuleを使用してNode.jsでWebサーバーを作成する方法に関するガイドをお読みください。

次のコードをテキストエディタに入力します。

デバッガー/server.js
const http = require("http");

const host = 'localhost';
const port = 8000;

const greetings = ["Hello world", "Hola mundo", "Bonjour le monde", "Hallo Welt", "Salve mundi"];

const getGreeting = function () {
  let greeting = greetings[Math.floor(Math.random() * greetings.length)];
  return greeting
}

まず、インポートします http モジュール。HTTPサーバーを作成するために必要です。 次に、 hostport 後でサーバーを実行するために使用する変数。 The greetings 配列には、サーバーが返すことができるすべての可能な挨拶が含まれています。 The getGreeting() 関数はあいさつをランダムに選択して返します。

HTTPリクエストを処理するリクエストリスナーを追加し、サーバーを実行するためのコードを追加しましょう。 次のように入力して、Node.jsモジュールの編集を続けます。

デバッガー/server.js
...

const requestListener = function (req, res) {
  let message = getGreeting();
  res.setHeader("Content-Type", "application/json");
  res.writeHead(200);
  res.end(`{"message": "${message}"}`);
};

const server = http.createServer(requestListener);
server.listen(port, host, () => {
  console.log(`Server is running on http://${host}:${port}`);
});

これでサーバーを使用する準備ができたので、Chromeデバッガーをセットアップしましょう。

次のコマンドでChromeデバッガーを起動できます。

  1. node --inspect server.js

注:CLIデバッガーとChromeデバッガーのコマンドの違いに注意してください。 使用するCLIを使用する場合 inspect. Chromeを使用する場合は --inspect.

デバッガーを起動すると、次の出力が表示されます。

Output
Debugger listening on ws://127.0.0.1:9229/996cfbaf-78ca-4ebd-9fd5-893888efe8b3 For help, see: https://nodejs.org/en/docs/inspector Server is running on http://localhost:8000

次に、GoogleChromeまたはChromiumを開いて次のように入力します chrome://inspect アドレスバーにあります。 Microsoft EdgeもV8JavaScriptエンジンを使用しているため、同じデバッガーを使用できます。 Microsoft Edgeを使用している場合は、次の場所に移動します edge://inspect.

URLに移動すると、次のページが表示されます。

Devices ヘッダーの下で、ノード専用のDevToolsを開くボタンをクリックします。 新しいウィンドウがポップアップ表示されます。

これで、ChromeでNode.jsコードをデバッグできるようになりました。 ソースタブがまだ表示されていない場合は、そこに移動します。 左側で、ファイルツリーを展開し、[ server.js:

コードにブレークポイントを追加しましょう。 サーバーが挨拶を選択し、それを返そうとしているときに停止したいと思います。 デバッグコンソールで行番号10をクリックします。 番号の横に赤い点が表示され、右側のパネルに新しいブレークポイントが追加されたことを示します。

次に、ウォッチ式を追加しましょう。 右側のパネルで、 Watch ヘッダーの横にある矢印をクリックしてウォッチワードリストを開き、+をクリックします。 入る greeting を押して ENTER リクエストを処理するときにその値を観察できるようにします。

次に、コードをデバッグしましょう。 新しいブラウザウィンドウを開き、に移動します http://localhost:8000-Node.jsサーバーが実行されているアドレス。 押すと ENTER、すぐに返信はありません。 代わりに、デバッグウィンドウがもう一度ポップアップ表示されます。 すぐにフォーカスが合わない場合は、デバッグウィンドウに移動して次のことを確認してください。

デバッガーは、ブレークポイントを設定したサーバーの応答を一時停止します。 監視している変数は、右側のパネルと、それを作成したコード行で更新されます。

ブレークポイントで一時停止のすぐ上にある右側のパネルの続行ボタンを押して、応答の実行を完了しましょう。 応答が完了すると、Node.jsサーバーとの通信に使用されるブラウザーウィンドウに成功したJSON応答が表示されます。

{"message": "Hello world"}

このように、Chrome DevToolsは、ブレークポイントを追加するためにコードを変更する必要はありません。 コマンドラインでグラフィカルアプリケーションを使用してデバッグする場合は、ChromeDevToolsの方が適しています。

結論

この記事では、アプリケーションの状態を監視するウォッチャーを設定し、プログラムの実行のさまざまな時点で実行を一時停止できるようにブレークポイントを追加することで、サンプルのNode.jsアプリケーションをデバッグしました。 これは、組み込みのCLIデバッガーとGoogleChromeのDevToolsの両方を使用して実現しました。

多くのNode.js開発者は、コードをデバッグするためにコンソールにログオンします。 これは便利ですが、実行を一時停止してさまざまな状態の変化を監視できるほど柔軟ではありません。 このため、デバッグツールを使用する方が効率的であることが多く、プロジェクトの開発中に時間を節約できます。

これらのデバッグツールの詳細については、Node.jsのドキュメントまたはChromeDevToolsのドキュメントをご覧ください。 Node.jsの学習を継続したい場合は、 Node.jsシリーズのコーディング方法に戻るか、Nodeトピックページでプログラミングプロジェクトとセットアップを参照してください。