前端调试devtools_如何使用内置调试器和Chrome DevTools调试Node.js

前端调试devtools

The author selected the COVID-19 Relief Fund to receive a donation as part of the Write for DOnations program.

作者选择了COVID-19救济基金来接受捐赠,这是Write for DOnations计划的一部分。

介绍 (Introduction)

In Node.js development, tracing a coding error back to its source can save a lot of time over the course of a project. But as a program grows in complexity, it becomes harder and harder to do this efficiently. To solve this problem, developers use tools like a debugger, a program that allows developers to inspect their program as it runs. By replaying the code line-by-line and observing how it changes the program’s state, debuggers can provide insight into how a program is running, making it easier to find bugs.

在Node.js开发中,将编码错误追溯到其源头可以在项目过程中节省大量时间。 但是随着程序复杂性的增加,有效地执行此操作变得越来越困难。 为了解决此问题,开发人员使用诸如调试器之类的工具,该程序允许开发人员在其运行时检查其程序。 通过逐行回放代码并观察其如何更改程序状态,调试器可以洞悉程序的运行方式,从而更容易发现错误。

A common practice programmers use to track bugs in their code is to print statements as the program runs. In Node.js, that involves adding extra console.log() or console.debug() statements in their modules. While this technique can be used quickly, it is also manual, making it less scalable and more prone to errors. Using this method, it is possible to mistakenly log sensitive information to the console, which could provide malicious agents with private information about customers or your application. On the other hand, debuggers provide a systematic way to observe what’s happening in a program, without exposing your program to security threats.

程序员用来跟踪其代码中的错误的常见做法是在程序运行时打印语句。 在Node.js中,这涉及在其模块中添加额外的console.log()console.debug()语句。 尽管可以快速使用此技术,但它也是手动的,因此扩展性较差,更容易出错。 使用此方法,可能会错误地将敏感信息记录到控制台,这可能会向恶意代理提供有关客户或您的应用程序的私人信息。 另一方面,调试器提供了一种系统的方式来观察程序中发生的事情,而不会使您的程序受到安全威胁。

The key features of debuggers are watching objects and adding breakpoints. By watching objects, a debugger can help track the changes of a variable as the programmer steps through a program. Breakpoints are markers that a programmer can place in their code to stop the code from continuing beyond points that the developer is investigating.

调试器的主要功能是监视对象并添加断点 。 通过观察对象,调试器可以在程序员逐步执行程序时帮助跟踪变量的变化。 断点是程序员可以在其代码中放置的标记,以阻止代码继续超出开发人员正在调查的点。

In this article, you will use a debugger to debug some sample Node.js applications. You will first debug code using the built-in Node.js debugger tool, setting up watchers and breakpoints so you can find the root cause of a bug. You will then use Google Chrome DevTools as a Graphical User Interface (GUI) alternative to the command line Node.js debugger.

在本文中,您将使用调试器来调试一些示例Node.js应用程序。 首先,您将使用内置的Node.js调试器工具调试代码,设置观察程序和断点,以便找到错误的根本原因。 然后,您将使用Google Chrome DevTools作为命令行Node.js调试器的替代图形用户界面(GUI)

先决条件 (Prerequisites)

第1步-将Watchers与Node.js调试器一起使用 (Step 1 — Using Watchers with the Node.js Debugger)

Debuggers are primarily useful for two features: their ability to watch variables and observe how they change when a program is run and their ability to stop and start code execution at different locations called breakpoints. In this step, we will run through how to watch variables to identify errors in code.

调试器主要用于以下两个功能: 监视变量并观察程序运行时它们如何变化的能力,以及在称为断点的不同位置停止和启动代码执行的能力。 在这一步中,我们将介绍如何监视变量以识别代码中的错误。

Watching variables as we step through code gives us insight into how the values of variables change as the program runs. Let’s practice watching variables to help us find and fix logical errors in our code with an example.

在逐步查看代码时观察变量可以使我们深入了解变量值在程序运行时如何变化。 让我们练习观察变量,以帮助我们举例说明并修复代码中的逻辑错误。

We begin by setting up our coding environment. In your terminal, create a new folder called debugging:

我们首先建立我们的编码环境。 在您的终端中,创建一个名为debugging的新文件夹:

  • mkdir debugging

    mkdir调试

Now enter that folder:

现在输入该文件夹:

  • cd debugging

    cd调试

Open a new file called badLoop.js. We will use nano as it’s available in the terminal:

打开一个名为badLoop.js的新文件。 我们将使用nano因为它在终端中可用:

  • nano badLoop.js

    纳米badLoop.js

Our code will iterate over an array and add numbers into a total sum, which in our example will be used to add up the number of daily orders over the course of a week at a store. The program will return the sum of all the numbers in the array. In the editor, enter the following code:

我们的代码将遍历一个数组 ,并将数字加到一个总和中,在我们的示例中,它将用于累加一周中在一家商店中的每日订单数。 程序将返回数组中所有数字的总和。 在编辑器中,输入以下代码:

debugging/badLoop.js
调试/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);

We start by creating the orders array, which stores five numbers. We then initialize totalOrders to 0, as it will store the total of the five numbers. In the for loop, we iteratively add each value in orders to totalOrders. Finally, we print the total amount of orders at the end of the program.

我们首先创建orders数组,该数组存储五个数字。 然后,我们将totalOrders初始化为0 ,因为它将存储五个数字的总数。 在for循环中 ,我们迭代地将orders每个值添加到totalOrders 。 最后,我们在程序结束时打印订单总数。

Save and exit from the editor. Now run this program with node:

保存并退出编辑器。 现在使用node运行该程序:

  • node badLoop.js

    节点badLoop.js

The terminal will show this output:

终端将显示以下输出:


   
   
Output
NaN

NaN in JavaScript means Not a Number. Given that all the input are valid numbers, this is unexpected behavior. To find the error, let’s use the Node.js debugger to see what happens to the two variables that are changed in the for loop: totalOrders and i.

JavaScript中的NaN表示不是数字 。 鉴于所有输入均为有效数字,这是意外行为。 为了找到错误,让我们使用Node.js调试器来查看在for循环中更改的两个变量的结果: totalOrdersi

When we want to use the built-in Node.js debugger on a program, we include inspect before the file name. In your terminal, run the node command with this debugger option as follows:

当我们想在程序上使用内置的Node.js调试器时,我们在文件名之前包括inspect 。 在您的终端中,使用以下调试器选项运行node命令,如下所示:

  • node inspect badLoop.js

    节点检查badLoop.js

When you start the debugger, you will find output like this:

启动调试器时,您将找到如下输出:


   
   
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;

The first line shows us the URL of our debug server. That’s used when we want to debug with external clients, like a web browser as we’ll see later on. Note that this server listens on port :9229 of the localhost (127.0.0.1) by default. For security reasons, it is recommended to avoid exposing this port to the public.

第一行向我们显示了调试服务器的URL。 当我们要使用外部客户端进行调试时(例如稍后将要看到的Web浏览器),将使用该功能。 请注意,默认情况下,此服务器在localhost ( 127.0.0.1 )的端口:9229进行侦听。 出于安全原因,建议避免将此端口公开。

After the debugger is attached, the debugger outputs Break on start in badLoop.js:1.

附加调试器后,调试器Break on start in badLoop.js:1输出Break on start in badLoop.js:1

Breakpoints are places in our code where we’d like execution to stop. By default, Node.js’s debugger stops execution at the beginning of the file.

断点是代码中我们希望停止执行的位置。 默认情况下,Node.js的调试器在文件的开头停止执行。

The debugger then shows us a snippet of code, followed by a special debug prompt:

然后,调试器向我们显示了一段代码,然后是一个特殊的debug提示:


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

The > next to 1 indicates which line we’ve reached in our execution, and the prompt is where we will type in our commends to the debugger. When this output appears, the debugger is ready to accept commands.

1旁边的>表示我们在执行过程中到达了哪一行,并在提示符下键入调试器的命令。 当出现此输出时,调试器已准备就绪,可以接受命令。

When using a debugger, we step through code by telling the debugger to go to the next line that the program will execute. Node.js allows the following commands to use a debugger:

使用调试器时,我们通过告诉调试器转到程序将要执行的下一行来逐步执行代码。 Node.js允许以下命令使用调试器:

  • c or cont: Continue execution to the next breakpoint or to the end of the program.

    ccont :继续执行到下一个断点或程序的结尾。

  • n or next: Move to the next line of code.

    nnext :移至下一行代码。

  • s or step: Step into a function. By default, we only step through code in the block or scope we’re debugging. By stepping into a function, we can inspect the code of the function our code calls and observe how it reacts to our data.

    sstep :步骤成一个函数。 默认情况下,我们仅在调试的块或作用域中单步执行代码。 通过进入一个函数,我们可以检查代码调用的函数代码,并观察它如何对我们的数据做出React。

  • o: Step out of a function. After stepping into a function, the debugger goes back to the main file when the function returns. We can use this command to go back to the original function we were debugging before the function has finished execution.

    o :退出功能。 进入函数后,当函数返回时,调试器将返回主文件。 我们可以使用该命令返回到我们正在调试的原始函数,直到函数执行完毕。

  • pause: Pause the running code.

    pause :暂停正在运行的代码。

We’ll be stepping through this code line-by-line. Press n to go to the next line:

我们将逐行逐步执行此代码。 按n转到下一行:

  • n

    ñ

Our debugger will now be stuck on the third line of code:

现在,我们的调试器将停留在第三行代码中:


   
   
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++) {

Empty lines are skipped for convenience. If we press n once more in the debug console, our debugger will be situated on the fifth line of code:

为方便起见,跳过了空行。 如果在调试控制台中再按一次n ,则调试器将位于代码的第五行:


   
   
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 }

We are now beginning our loop. If the terminal supports color, the 0 in let i = 0 will be highlighted. The debugger highlights the part of the code the program is about to execute, and in a for loop, the counter initialization is executed first. From here, we can watch to see why totalOrders is returning NaN instead of a number. In this loop, two variables are changed every iteration—totalOrders and i. Let’s set up watchers for both of those variables.

我们现在开始循环。 如果终端支持颜色, 0let i = 0将被突出显示。 调试器突出显示程序将要执行的部分代码,并在for循环中,首先执行计数器初始化。 从这里,我们可以看到为什么totalOrders返回NaN而不是数字。 在此循环中,每次迭代totalOrders更改两个变量totalOrdersi 。 让我们为这两个变量设置观察者。

We’ll first add a watcher for the totalOrders variable. In the interactive shell, enter this:

我们将首先为totalOrders变量添加一个观察者。 在交互式外壳中,输入以下内容:

  • watch('totalOrders')

    看('totalOrders')

To watch a variable, we use the built-in watch() function with a string argument that contains the variable name. As we press ENTER on the watch() function, the prompt will move to the next line without providing feedback, but the watch word will be visible when we move the debugger to the next line.

要监视变量,我们将内置的watch()函数与包含变量名称的字符串参数一起使用。 当我们在watch()函数上按ENTER时,提示将移至下一行而不提供反馈,但是当我们将调试器移至下一行时,监视字将可见。

Now let’s add a watcher for the variable i:

现在让我们为变量i添加一个观察者:

  • watch('i')

    看('i')

Now we can see our watchers in action. Press n to go to the next step. The debug console will show this:

现在我们可以看到观察者在行动了。 按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 }

The debugger now displays the values of totalOrders and i before showing the line of code, as shown in the output. These values are updated every time a line of code changes them.

调试器现在在显示代码行之前显示totalOrdersi的值,如输出所示。 每当一行代码更改它们时,这些值就会更新。

At this point, the debugger is highlighting length in orders.length. This means the program is about to check the condition before it executes the code within its block. After the code is executed, the final expression i++ will be executed. You can read more about for loops and their execution in our How To Construct For Loops in JavaScript guide.

此时,调试器将在orders.length突出显示length 。 这意味着程序将在执行其块内的代码之前检查条件。 执行代码后,将执行最终表达式i++ 。 您可以在我们的《 如何在JavaScript中构造For循环》指南中了解有关for循环及其执行的更多信息。

Enter n in the console to enter the for loop’s body:

在控制台中输入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

This step updates the totalOrders variable. Therefore, after this step is complete our variable and watcher will be updated.

此步骤将更新totalOrders变量。 因此,完成此步骤后,我们的变量和观察者将被更新。

Press n to confirm. You will see this:

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 }

As highlighted, totalOrders now has the value of the first order: 341.

如突出显示的那样, totalOrders现在具有第一个订单的值: 341

Our debugger is just about to process the final condition of the loop. Enter n so we execute this line and update i:

我们的调试器将要处理循环的最终条件。 输入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 }

After initialization, we had to step through the code four times to see the variables updated. Stepping through the code like this can be tedious; this problem will be addressed with breakpoints in Step 2. But for now, by setting up our watchers, we are ready to observe their values and find our problem.

初始化之后,我们必须四遍遍代码以查看变量已更新。 像这样单步执行代码可能很乏味。 这个问题将在步骤2中用断点解决。 但是目前,通过设置观察者,我们准备观察他们的价值观并发现我们的问题。

Step through the program by entering n twelve more times, observing the output. Your console will display this:

通过再输入12次n逐步执行程序,并观察输出。 您的控制台将显示以下内容:


   
   
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 }

Recall that our orders array has five items, and i is now at position 5. But since i is used as the index of an array, there is no value at orders[5]; the last value of the orders array is at index 4. This means that orders[5] will have a value of undefined.

回想一下,我们的orders数组有五个项目,而i现在处于位置5 。 但是由于i用作数组的索引,所以orders[5]没有值; orders数组的最后一个值在索引4 。 这意味着orders[5]的值将为undefined

Type n in the console and you’ll observe that the code in the loop is executed:

在控制台中输入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

Typing n once more shows the value of totalOrders after that iteration:

再次键入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 }

Through debugging and watching totalOrders and i, we can see that our loop is iterating six times instead of five. When i is 5, orders[5] is added to totalOrders. Since orders[5] is undefined, adding this to a number will yield NaN. The problem with our code therefore lies within our for loop’s condition. Instead of checking if i is less than or equal to the length of the orders array, we should only check that it’s less than the length.

通过调试和观察totalOrdersi ,我们可以看到我们的循环迭代了六次而不是五次。 当i5orders[5]被添加到totalOrders 。 由于orders[5]undefined ,因此将其添加到数字将产生NaN 。 因此,我们代码的问题就在我们的for循环条件内。 而不是检查i是否小于或等于orders数组的长度,我们应该只检查它是否小于长度。

Let’s exit our debugger, make the changes and run the code again. In the debug prompt, type the exit command and press ENTER:

让我们退出调试器,进行更改,然后再次运行代码。 在调试提示中,键入exit命令,然后按ENTER

  • .exit

    。出口

Now that you’ve exited the debugger, open badLoop.js in your text editor:

退出调试器后,在文本编辑器中打开badLoop.js

  • nano badLoop.js

    纳米badLoop.js

Change the for loop’s condition:

更改for循环的条件:

debugger/badLoop.js
调试器/badLoop.js
...
for (let i = 0; i < orders.length; i++) {
...

Save and exit nano. Now let’s execute our script like this:

保存并退出nano 。 现在让我们像这样执行脚本:

  • node badLoop.js

    节点badLoop.js

When it’s complete, the correct result will be printed:

完成后,将打印正确的结果:


   
   
Output
1564

In this section, we used the debugger’s watch command to find a bug in our code, fixed it, and watched it work as expected.

在本节中,我们使用调试器的watch命令在代码中查找错误,对其进行了修复,并观察了它是否按预期工作。

Now that we have some experience with the basic use of the debugger to watch variables, let’s look at how we can use breakpoints so that we can debug without stepping through all the lines of code from the start of the program.

既然我们已经掌握了调试器监视变量的基本经验,那么让我们看一下如何使用断点,以便我们可以进行调试,而无需从程序开始就逐步执行所有代码行。

第2步-在Node.js调试器中使用断点 (Step 2 — Using Breakpoints With the Node.js Debugger)

It’s common for Node.js projects to consist of many interconnected modules. Debugging each module line-by-line would be time consuming, especially as an app scales in complexity. To solve this problem, breakpoints allow us to jump to a line of code where we’d like to pause execution and inspect the program.

Node.js项目通常由许多相互连接的模块组成 。 逐行调试每个模块非常耗时,尤其是在应用程序扩展复杂性时。 为了解决这个问题,可以使用断点跳转到一行代码,在该代码行中我们希望暂停执行并检查程序。

When debugging in Node.js, we add a breakpoint by adding the debugger keyword directly to our code. We can then go from one breakpoint to the next by pressing c in the debugger console instead of n. At each breakpoint, we can set up watchers for expressions of interest.

在Node.js中进行调试时,我们通过将debugger关键字直接添加到代码中来添加断点。 然后,通过在调试器控制台中按c而不是n可以从一个断点转到下一个断点。 在每个断点处,我们可以设置观察者以表达兴趣。

Let’s see this with an example. In this step, we’ll set up a program that reads a list of sentences and determines the most common word used throughout all the text. Our sample code will return the first word with the highest number of occurrences.

让我们看一个例子。 在这一步中,我们将设置一个程序,该程序读取句子列表并确定在所有文本中使用的最常见单词。 我们的示例代码将返回出现次数最多的第一个单词。

For this exercise, we will create three files. The first file, sentences.txt, will contain the raw data that our program will process. We’ll add the beginning text from Encyclopaedia Britannica’s article on the Whale Shark as sample data, with the punctuation removed.

在本练习中,我们将创建三个文件。 第一个文件, sentences.txt ,将包含我们程序将处理的原始数据。 我们将添加大不列颠百科全书关于鲸鲨的文章的开头文本作为示例数据,并删除标点符号。

Open the file in your text editor:

在文本编辑器中打开文件:

  • nano sentences.txt

    纳米句子.txt

Next, enter the following code:

接下来,输入以下代码:

debugger/sentences.txt
debugger / 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

Save and exit the file.

保存并退出文件。

Now let’s add our code to textHelper.js. This module will contain some handy functions we’ll use to process the text file, making it easier to determine the most popular word. Open textHelper.js in your text editor:

现在,将代码添加到textHelper.js 。 该模块将包含一些方便的功能,我们将使用这些功能来处理文本文件,从而更容易确定最受欢迎的单词。 在文本编辑器中打开textHelper.js

  • nano textHelper.js

    纳米textHelper.js

We’ll create three functions to process the data in sentences.txt. The first will be to read the file. Type the following into textHelper.js:

我们将创建三个函数来处理sentences.txt中的数据。 首先将是读取文件。 在textHelper.js输入以下textHelper.js

debugger/textHelper.js
调试器/textHelper.js
const fs = require('fs');

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

First, we import the fs Node.js library so we can read files. We then create the readFile() function that uses readFileSync() to load the data from sentences.txt as a Buffer object and the toString() method to return it as a string.

首先,我们导入fs Node.js库,以便读取文件。 然后,我们创建readFile()函数,该函数使用readFileSync()sentences.txt readFileSync()加载数据作为Buffer对象,并使用toString()方法将其作为字符串返回。

The next function we’ll add processes a string of text and flattens it to an array with its words. Add the following code into the editor:

我们将添加的下一个函数处理文本字符串,并将其展平到带有单词的数组。 将以下代码添加到编辑器中:

textHelper.js
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;
};

In this code, we are using the methods split(), join(), and map() to manipulate the string into an array of individual words. The function also lowercases each word to make counting easier.

在这段代码中,我们使用split()join()map()方法将字符串操纵为单个单词的数组。 该功能还小写每个单词,使计数更容易。

The last function needed returns the counts of different words in a string array. Add the last function like this:

最后一个需要的函数返回字符串数组中不同单词的计数。 添加最后一个函数,如下所示:

debugger/textHelper.js
调试器/textHelper.js
...

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

  return map;
};

Here we create a JavaScript object called map that has the words as its keys and their counts as the values. We loop through the array, adding one to a count of each word when it’s the current element of the loop. Let’s complete this module by exporting these functions, making them available to other modules:

在这里,我们创建了一个称为mapJavaScript对象 ,该对象具有单词作为键,其计数作为值。 我们遍历数组,当它是循环的当前元素时,在每个单词的计数中加一个。 让我们通过导出以下功能来完善该模块,使其可用于其他模块:

debugger/textHelper.js
调试器/textHelper.js
...

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

Save and exit.

保存并退出。

Our third and final file we’ll use for this exercise will use the textHelper.js module to find the most popular word in our text. Open index.js with your text editor:

我们将在本练习中使用的第三个也是最后一个文件将使用textHelper.js模块查找文本中最受欢迎的单词。 使用文本编辑器打开index.js

  • nano index.js

    纳米index.js

We begin our code by importing the textHelpers.js module:

我们通过导入textHelpers.js模块开始我们的代码:

debugger/index.js
调试器/index.js
const textHelper = require('./textHelper');

Continue by creating a new array containing stop words:

继续创建一个包含停用词的新数组:

debugger/index.js
调试器/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', ''];

Stop words are commonly used words in a language that we filter out before processing a text. We can use this to find more meaningful data than the result that the most popular word in English text is the or a.

停用词是我们在处理文本之前过滤掉的语言中常用的词。 我们可以用它来找到比的结果是,在英文文本中最流行的词是更有意义的数据thea

Continue by using the textHelper.js module functions to get a JavaScript object with words and their counts:

通过使用textHelper.js模块函数继续获取带有单词及其计数JavaScript对象:

debugger/index.js
调试器/index.js
...

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

We can then complete this module by determining the words with the highest frequency. To do this, we’ll loop through each key of the object with the word counts and compare its count to the previously stored maximum. If the word’s count is higher, it becomes the new maximum.

然后,我们可以通过确定频率最高的单词来完成此模块。 为此,我们将遍历对象的每个键以及单词计数,并将其计数与先前存储的最大值进行比较。 如果单词的数量更多,它将成为新的最大值。

Add the following lines of code to compute the most popular word:

添加以下代码行以计算最受欢迎的单词:

debugger/index.js
调试器/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`);

In this code, we are using Object.entries() to transform the key-value pairs in the wordCounts object into individual arrays, all of which are nested within a larger array. We then use the forEach() method and some conditional statements to test the count of each word and store the highest number.

在这段代码中,我们使用Object.entries()wordCounts对象中的wordCounts对转换为单独的数组,所有这些嵌套在一个更大的数组中。 然后,我们使用forEach()方法和一些条件语句来测试每个单词的计数并存储最高的数字。

Save and exit the file.

保存并退出文件。

Let’s now run this file to see it in action. In your terminal enter this command:

现在让我们运行该文件以查看其运行情况。 在您的终端中输入以下命令:

  • node index.js

    节点index.js

You will see the following output:

您将看到以下输出:


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

From reading the text, we can see that the answer is incorrect. A quick search in sentences.txt would highlight that the word whale appears more than once.

通过阅读文字,我们可以看到答案是错误的。 在sentences.txt .txt中快速搜索将突出显示“ whale ”一词出现了不止一次。

We have quite a few functions that can cause this error: We may not be reading the entire file, or we may not be processing the text into the array and JavaScript object correctly. Our algorithm for finding the maximum word could also be incorrect. The best way to figure out what’s wrong is to use the debugger.

我们有很多函数可能导致此错误:我们可能没有读取整个文件,或者我们没有正确地将文本处理到数组和JavaScript对象中。 我们用于查找最大单词的算法也可能不正确。 找出问题所在的最佳方法是使用调试器。

Even without a large codebase, we don’t want to spend time stepping through each line of code to observe when things change. Instead, we can use breakpoints to go to those key moments before the function returns and observe the output.

即使没有大型的代码库,我们也不想花时间逐步浏览每一行代码来观察何时发生更改。 相反,我们可以使用断点转到函数返回之前的关键时刻并观察输出。

Let’s add breakpoints in each function in the textHelper.js module. To do so, we need to add the keyword debugger into our code.

让我们在textHelper.js模块的每个函数中添加断点。 为此,我们需要在代码中添加关键字debugger

Open the textHelper.js file in the text editor. We’ll be using nano once again:

在文本编辑器中打开textHelper.js文件。 我们将再次使用nano

  • nano textHelper.js

    纳米textHelper.js

First, we’ll add the breakpoint to the readFile() function like this:

首先,我们将断点添加到readFile()函数中,如下所示:

debugger/textHelper.js
调试器/textHelper.js
...

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

...

Next, we’ll add another breakpoint to the getWords() function:

接下来,我们将向getWords()函数添加另一个断点:

debugger/textHelper.js
调试器/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;
};

...

Finally, we’ll add a breakpoint to the countWords() function:

最后,我们将一个断点添加到countWords()函数中:

debugger/textHelper.js
调试器/textHelper.js
...

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

  debugger;
  return map;
};

...

Save and exit textHelper.js.

保存并退出textHelper.js

Let’s begin the debugging process. Although the breakpoints are in textHelpers.js, we are debugging the main point of entry of our application: index.js. Start a debugging session by entering the following command in your shell:

让我们开始调试过程。 尽管断点位于textHelpers.js ,但我们正在调试应用程序的主要入口点: index.js 。 通过在shell中输入以下命令来启动调试会话:

  • node inspect index.js

    节点检查index.js

After entering the command, we’ll be greeted with this output:

输入命令后,我们将看到以下输出:


   
   
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', ''];

This time, enter c into the interactive debugger. As a reminder, c is short for continue. This jumps the debugger to the next breakpoint in the code. After pressing c and typing ENTER, you will see this in your console:

这次,将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 };

We’ve now saved some debugging time by going directly to our breakpoint.

现在,我们直接转到断点,从而节省了一些调试时间。

In this function, we want to be sure that all the text in the file is being returned. Add a watcher for the sentences variable so we can see what’s being returned:

在此功能中,我们要确保返回文件中的所有文本。 为sentences变量添加一个观察器,以便我们可以看到返回的内容:

  • watch('sentences')

    看('句子')

Press n to move to the next line of code so we can observe what’s in sentences. You will see the following output:

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

It seems that we aren’t having any problems reading the file; the problem must lie elsewhere in our code. Let’s move to the next breakpoint by pressing c once again. When you do, you’ll see this output:

看来我们在读取文件时没有任何问题; 问题必须出在我们代码的其他地方。 让我们再次按下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 };

We get this error message because we set up a watcher for the sentences variable, but that variable does not exist in our current function scope. A watcher lasts for the entire debugging session, so as long as we keep watching sentences where it’s not defined, we’ll continue to see this error.

我们收到此错误消息是因为我们为sentences变量设置了监视程序,但是该变量在当前函数范围中不存在。 一个观察者会持续整个调试会话,因此,只要我们继续观察未定义sentences地方,我们就会继续看到此错误。

We can stop watching variables with the unwatch() command. Let’s unwatch sentences so we no longer have to see this error message every time the debugger prints its output. In the interactive prompt, enter this command:

我们可以使用unwatch()命令停止监视变量。 让我们不用看sentences这样我们就不必在每次调试器打印输出时都看到此错误消息。 在交互式提示中,输入以下命令:

  • unwatch('sentences')

    监视('句子')

The debugger does not output anything when you unwatch a variable.

取消监视变量时,调试器不会输出任何内容。

Back in the getWords() function, we want to be sure that we are returning a list of words that are taken from the text we loaded earlier. Let’s watch the value of the words variable:

回到getWords()函数中,我们要确保返回的是从先前加载的文本中提取的单词列表。 让我们看一下words变量的值:

  • watch('words')

    看('words')

Then enter n to go to the next line of the debugger, so we can see what’s being stored in words. The debugger will show the following:

然后输入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

The debugger does not print out the entire array as it’s quite long and would make the output harder to read. However, the output meets our expectations of what should be stored: the text from sentences split into lowercase strings. It seems that getWords() is functioning correctly.

调试器不会打印出整个数组,因为它很长,会使输出难以阅读。 但是,输出结果符合我们对应存储内容的期望: sentences的文本分为小写字符串。 看来getWords()正常运行。

Let’s move on to observe the countWords() function. First, unwatch the words array so we don’t cause any debugger errors when we are at the next breakpoint. In the command prompt, enter this:

让我们继续观察countWords()函数。 首先,取消监视words数组,以便在下一个断点时不会引起任何调试器错误。 在命令提示符下,输入以下内容:

  • unwatch('words')

    监视('words')

Next, enter c in the prompt. At our last breakpoint, we will see this in the shell:

接下来,在提示符下输入c 。 在最后一个断点处,我们将在shell中看到以下内容:


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

In this function, we want to be sure that the map variable correctly contains the count of each word from our sentences. First, let’s tell the debugger to watch the map variable:

在此功能中,我们要确保map变量正确包含句子中每个单词的计数。 首先,让我们告诉调试器观看map变量:

  • watch('map')

    看('地图')

Press n to move to the next line. The debugger will then display this:

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

That does not look correct. It seems as though the method for counting words is producing erroneous results. We don’t know why those values are being entered, so our next step is to debug what’s happening in the loop used on the words array. To do this, we need to make some changes to where we place our breakpoint.

看起来不正确。 似乎字数统计方法产生了错误的结果。 我们不知道为什么要输入这些值,所以我们的下一步是调试在words数组上使用的循环中发生的情况。 为此,我们需要对放置断点的位置进行一些更改。

First, exit the debug console:

首先,退出调试控制台:

  • .exit

    。出口

Open textHelper.js in your text editor so we can edit the breakpoints:

在您的文本编辑器中打开textHelper.js ,以便我们编辑断点:

  • nano textHelper.js

    纳米textHelper.js

First, knowing that readFile() and getWords() are working, we will remove their breakpoints. We then want to remove the breakpoint in countWords() from the end of the function, and add two new breakpoints to the beginning and end of the forEach() block.

首先,知道readFile()getWords()正常工作后,我们将删除它们的断点。 然后,我们要从函数的末尾删除countWords()中的断点,并在forEach()块的开头和结尾添加两个新的断点。

Edit textHelper.js so it looks like this:

编辑textHelper.js ,使其如下所示:

debugger/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;
};

...

Save and exit nano with CTRL+X.

使用CTRL+X保存并退出nano

Let’s start the debugger again with this command:

让我们再次使用以下命令启动调试器:

  • node inspect index.js

    节点检查index.js

To get insight into what’s happening, we want to debug a few things in the loop. First, let’s set up a watcher for word, the argument used in the forEach() loop containing the string that the loop is currently looking at. In the debug prompt, enter this:

为了洞悉正在发生的事情,我们想在循环中调试一些东西。 首先,让我们为word设置观察者,它在forEach()循环中使用,包含循环当前正在查看的字符串。 在调试提示中,输入以下内容:

  • watch('word')

    看('word')

So far, we have only watched variables. But watches are not limited to variables. We can watch any valid JavaScript expression that’s used in our code.

到目前为止,我们仅关注变量。 但是手表不仅限于变量。 我们可以观察代码中使用的任何有效JavaScript表达式。

In practical terms, we can add a watcher for the condition word in map, which determines how we count numbers. In the debug prompt, create this watcher:

实际上,我们可以为word in map的条件word in map添加观察者,该观察者确定我们如何计算数字。 在调试提示中,创建此监视程序:

  • watch('word in map')

    观看(“地图中的单词”)

Let’s also add a watcher for the value that’s being modified in the map variable:

我们还为map变量中正在修改的值添加一个观察器:

  • watch('map[word]')

    看('map [word]')

Watchers can even be expressions that aren’t used in our code but could be evaluated with the code we have. Let’s see how this works by adding a watcher for the length of the word variable:

观察者甚至可以是我们的代码中未使用过的表达式,但可以使用我们拥有的代码对其进行评估。 让我们通过添加word变量长度的监视程序来查看其工作原理:

  • watch('word.length')

    看('word.length')

Now that we’ve set up all our watchers, let’s enter c into the debugger prompt so we can see how the first element in the loop of countWords() is evaluated. The debugger will print this output:

现在我们已经设置了所有观察程序,让我们在调试器提示符下输入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;

The first word in the loop is whale. At this point, the map object has no key with whale as its empty. Following from that, when looking up whale in map, we get undefined. Lastly, the length of whale is 5. That does not help us debug the problem, but it does validate that we can watch any expression that could be evaluated with the code while debugging.

循环中的第一个单词是whale 。 此时, map对象没有whale为空的钥匙。 因此,在map查找whale时,我们undefined 。 最后, whale的长度是5 。 这并不能帮助我们调试问题,但可以验证我们可以在调试时观察可以用该代码求值的任何表达式。

Press c once more to see what’s changed by the end of the loop. The debugger will show this:

再按一次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

At the end of the loop, word in map is now true as the map variable contains a whale key. The value of map for the whale key is NaN, which highlights our problem. The if statement in countWords() is meant to set a word’s count to one if it’s new, and add one if it existed already.

在循环结束时word in map现在为true,因为map变量包含一个whale键。 whale钥匙的map的值为NaN ,这突出了我们的问题。 countWords()if语句用于将一个单词的计数(如果是新的countWords()设置为1,如果已经存在则添加一个。

The culprit is the if statement’s condition. We should set map[word] to 1 if the word is not found in map. Right now, we are adding one if word is found. At the beginning of the loop, map["whale"] is undefined. In JavaScript, undefined + 1 evaluates to NaN—not a number.

罪魁祸首是if语句的条件。 我们应该设定map[word]1 ,如果word中找不到map 。 现在,如果找到word ,我们将添加一个。 在循环开始时, undefined map["whale"] 。 在JavaScript中, undefined + 1等于NaN而不是数字。

The fix for this would be to change the condition of the if statement from (word in map) to (!(word in map)), using the ! operator to test if word is not in map. Let’s make that change in the countWords() function to see what happens.

解决方法是使用!if语句的条件从(word in map)更改为(!(word in map)) ! 操作员测试word是否在map 。 让我们在countWords()函数中进行更改,看看会发生什么。

First, exit the debugger:

首先,退出调试器:

  • .exit

    。出口

Now open the textHelper.js file with your text editor:

现在,使用文本编辑器打开textHelper.js文件:

  • nano textHelper.js

    纳米textHelper.js

Modify the countWords() function as follows:

修改countWords()函数,如下所示:

debugger/textHelper.js
调试器/textHelper.js
...

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

  return map;
};

...

Save and close the editor.

保存并关闭编辑器。

Now let’s run this file without a debugger. In the terminal, enter this:

现在,让我们在没有调试器的情况下运行此文件。 在终端中,输入以下内容:

  • node index.js

    节点index.js

The script will output the following sentence:

该脚本将输出以下句子:


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

This output seems a lot more likely than what we received before. With the debugger, we figured out which function caused the problem and which functions did not.

此输出似乎比我们之前收到的输出大得多。 使用调试器,我们可以找出哪个函数导致了问题,而哪些函数则没有。

We’ve debugged two different Node.js programs with the built-in CLI debugger. We are now able to set up breakpoints with the debugger keyword and create various watchers to observe changes in internal state. But sometimes, code can be more effectively debugged from a GUI application.

我们已经使用内置的CLI调试器调试了两个不同的Node.js程序。 现在,我们可以使用debugger关键字设置断点,并创建各种观察程序以观察内部状态的变化。 但是有时候,可以从GUI应用程序更有效地调试代码。

In the next section, we’ll use the debugger in Google Chrome’s DevTools. We’ll start the debugger in Node.js, navigate to a dedicated debugging page in Google Chrome, and set up breakpoints and watchers using the GUI.

在下一部分中,我们将在Google Chrome的DevTools中使用调试器。 我们将在Node.js中启动调试器,在Google Chrome中导航到专用调试页面,并使用GUI设置断点和观察程序。

第3步-使用Chrome DevTools调试Node.js (Step 3 — Debugging Node.js with Chrome DevTools)

Chrome DevTools is a popular choice for debugging Node.js in a web browser. As Node.js uses the same V8 JavaScript engine that Chrome uses, the debugging experience is more integrated than with other debuggers.

Chrome DevTools是在网络浏览器中调试Node.js的流行选择。 由于Node.js使用与Chrome使用的相同的V8 JavaScript引擎 ,因此与其他调试器相比,调试体验更加集成。

For this exercise, we’ll create a new Node.js application that runs an HTTP server and returns a JSON response. We’ll then use the debugger to set up breakpoints and gain deeper insight into what response is being generated for the request.

在本练习中,我们将创建一个新的Node.js应用程序,该应用程序运行HTTP服务器并返回JSON响应 。 然后,我们将使用调试器设置断点,并更深入地了解针对该请求生成的响应。

Let’s create a new file called server.js that will store our server code. Open the file in the text editor:

让我们创建一个名为server.js的新文件,该文件将存储我们的服务器代码。 在文本编辑器中打开文件:

  • nano server.js

    纳米server.js

This application will return a JSON with a Hello World greeting. It will have an array of messages in different languages. When a request is received, it will randomly pick a greeting and return it in a JSON body.

该应用程序将返回带有Hello World问候的JSON。 它将具有一系列不同语言的消息。 收到请求后,它将随机选择一个问候并将其返回到JSON正文中。

This application will run on our localhost server on port :8000. If you’d like to learn more about creating HTTP servers with Node.js, read our guide on How To Create a Web Server in Node.js with the HTTP Module.

该应用程序将在端口:8000上的localhost服务器上运行。 如果您想了解有关使用Node.js创建HTTP服务器的更多信息,请阅读有关如何使用HTTP模块在Node.js中创建Web服务器的指南。

Type the following code into the text editor:

在文本编辑器中键入以下代码:

debugger/server.js
调试器/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
}

We begin by importing the http module, which is needed to create an HTTP server. We then set up the host and port variables that we will use later to run the server. The greetings array contains all the possible greetings our server can return. The getGreeting() function randomly selects a greeting and returns it.

我们首先导入创建HTTP服务器所需的http模块。 然后,我们设置hostport变量,稍后将使用它们来运行服务器。 greetings数组包含我们的服务器可以返回的所有可能的问候。 getGreeting()函数随机选择一个问候并返回它。

Let’s add the request listener that processes HTTP requests and add code to run our server. Continue editing the Node.js module by typing the following:

让我们添加处理HTTP请求的请求侦听器,并添加代码以运行我们的服务器。 通过键入以下内容继续编辑Node.js模块:

debugger/server.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}`);
});

Our server is now ready for use, so let’s set up the Chrome debugger.

我们的服务器现在可以使用了,所以我们设置Chrome调试器。

We can start the Chrome debugger with the following command:

我们可以使用以下命令启动Chrome调试器:

  • node --inspect server.js

    节点-检查server.js

Note: Keep in mind the difference between the CLI debugger and the Chrome debugger commands. When using the CLI you use inspect. When using Chrome you use --inspect.

注意:请记住,CLI调试器和Chrome调试器命令之间的区别。 使用CLI时,请使用inspect 。 使用Chrome时,请使用--inspect

After starting the debugger, you’ll find the following output:

启动调试器后,您将找到以下输出:


   
   
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

Now open Google Chrome or Chromium and enter chrome://inspect in the address bar. Microsoft Edge also uses the V8 JavaScript engine, and can thus use the same debugger. If you are using Microsoft Edge, navigate to edge://inspect.

现在打开Goog​​le Chrome或Chromium,然后在地址栏中输入chrome://inspectMicrosoft Edge还使用V8 JavaScript引擎,因此可以使用相同的调试器。 如果您使用的是Microsoft Edge,请导航至edge://inspect

After navigating to the URL, you will see the following page:

导航到URL后,您将看到以下页面:

Under the Devices header, click the Open dedicated DevTools for Node button. A new window will pop up:

在“ 设备”标题下,单击“ 打开专用于节点的DevTools”按钮。 将会弹出一个新窗口:

We’re now able to debug our Node.js code with Chrome. Navigate to the Sources tab if not already there. On the left-hand side, expand the file tree and select server.js:

现在,我们可以使用Chrome调试Node.js代码。 导航到“ 源”选项卡(如果尚不存在)。 在左侧,展开文件树,然后选择server.js

Let’s add a breakpoint to our code. We want to stop when the server has selected a greeting and is about to return it. Click on the line number 10 in the debug console. A red dot will appear next to the number and the right-hand panel will indicate a new breakpoint was added:

让我们在代码中添加一个断点。 当服务器选择问候语并要返回问候语时,我们想停止。 在调试控制台中单击行号10 。 该数字旁边将出现一个红点,右侧面板将指示已添加一个新的断点:

Now let’s add a watch expression. On the right panel, click the arrow next to the Watch header to open the watch words list, then click +. Enter greeting and press ENTER so that we can observe its value when processing a request.

现在让我们添加一个监视表达式。 在右侧面板上,单击“ 监视”标题旁边的箭头以打开监视词列表,然后单击“ +” 。 输入greeting并按ENTER以便我们在处理请求时可以观察其值。

Next, let’s debug our code. Open a new browser window and navigate to http://localhost:8000—the address the Node.js server is running on. When pressing ENTER, we will not immediately get a response. Instead, the debug window will pop up once again. If it does not immediately come into focus, navigate to the debug window to see this:

接下来,让我们调试代码。 打开一个新的浏览器窗口,然后导航到http://localhost:8000 —运行Node.js服务器的地址。 当按ENTER ,我们不会立即得到响应。 相反,调试窗口将再次弹出。 如果没有立即成为焦点,请导航到调试窗口以查看此信息:

The debugger pauses the server’s response where we set our breakpoint. The variables that we watch are updated in the right panel and also in the line of code that created it.

调试器在设置断点的地方暂停服务器的响应。 我们观察的变量在右侧面板中以及在创建该变量的代码行中进行了更新。

Let’s complete the response’s execution by pressing the continue button at the right panel, right above Paused on breakpoint. When the response is complete, you will see a successful JSON response in the browser window used to speak with the Node.js server:

让我们按一下右侧面板上的“继续”按钮(在“ 断点暂停”上方)来完成响应的执行。 响应完成后,您将在用于与Node.js服务器对话的浏览器窗口中看到成功的JSON响应:

{"message": "Hello world"}

In this way, Chrome DevTools does not require changes to the code to add breakpoints. If you prefer to use graphical applications over the command line to debug, the Chrome DevTools are more suitable for you.

这样,Chrome DevTools不需要更改代码即可添加断点。 如果您希望通过命令行使用图形应用程序进行调试,则Chrome DevTools更适合您。

结论 (Conclusion)

In this article, we debugged sample Node.js applications by setting up watchers to observe the state of our application, and then by adding breakpoints to allow us to pause execution at various points in our program’s execution. We accomplished this using both the built-in CLI debugger and Google Chrome’s DevTools.

在本文中,我们通过设置观察者以观察应用程序的状态,然后添加断点以允许我们在程序执行的各个点暂停执行来调试示例Node.js应用程序。 我们使用内置的CLI调试器和Google Chrome的DevTools来完成此任务。

Many Node.js developers log to the console to debug their code. While this is useful, it’s not as flexible as being able to pause execution and watch various state changes. Because of this, using debugging tools is often more efficient, and will save time over the course of developing a project.

许多Node.js开发人员登录控制台以调试其代码。 尽管这很有用,但它不像能够暂停执行并观察各种状态变化那样灵活。 因此,使用调试工具通常会更高效,并且可以在开发项目的过程中节省时间。

To learn more about these debugging tools, you can read the Node.js documentation or the Chrome DevTools documentation. If you’d like to continue learning Node.js, you can return to the How To Code in Node.js series, or browse programming projects and setups on our Node topic page.

要了解有关这些调试工具的更多信息,请阅读Node.js文档Chrome DevTools文档 。 如果您想继续学习Node.js,可以返回“ 如何在Node.js中编码”系列 ,或者在Node主题页面上浏览编程项目和设置。

翻译自: https://www.digitalocean.com/community/tutorials/how-to-debug-node-js-with-the-built-in-debugger-and-chrome-devtools

前端调试devtools

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值