作者:Ivy Walobwa✏️
随着您的 Web 应用程序变得越来越复杂,掌握调试艺术变得至关重要。
有效的 JavaScript 调试不仅仅涉及修复错误。它需要了解您的代码在幕后如何工作,以确保您的应用程序顺利运行并提供最佳的用户体验。
缩小的代码,即在生产中到达用户的代码版本,针对性能进行了优化。然而,精简的代码对于调试来说可能是一场噩梦。当用户遇到错误时,在精简代码中重现和诊断问题通常具有挑战性。
但是,使用正确的工具,JavaScript 调试会变得更加容易。本文将探讨如何利用源映射来调试精简代码,并深入研究使用 Chrome DevTools 的其他技术来有效识别和解决 Web 应用程序中的问题。
我们将开发一个简单的应用程序,该应用程序会增加计数并将其记录到控制台上。此应用程序演示了精简代码如何使调试变得棘手,以及源映射如何帮助简化流程。
创建下面的 .js 文件并添加代码片段,如下所示:
1. src/counterCache.js
export const countCache = { previousCount: 0, currentCount: 0, totalCount: 0 } export function updateCache(currentCount, previousCount) { countCache.currentCount = currentCount; countCache.previousCount = previousCount; c ountCache.totalCount = countCache.totalCount + countCache.currentCount; }
2.src/counter.js:
import { updateCache } from './counterCache.js'; let count = 0; export function incrementCounter() { count += 1; const previousCount = count; updateCache(count, previousCount); }
3.src/index.js:
import { incrementCounter } from './counter'; import { countCache } from './counterCache'; const button = document.createElement('button'); const previousElement = document.getElementById('previous'); const currentElement = document.getElementById('current'); const totalElement = document.getElementById('total'); button.innerText = 'Click me'; document.body.appendChild(button); button.addEventListener('click', () => { incrementCounter(); previousElement.innerText = countCache.previousCount; currentElement.innerText = countCache.currentCount; totalElement.innerText = countCache.total(); });
在 package.json 文件中,添加如下所示的 webpack 包,然后运行 npm i 来安装它们。我们将使用 webpack 作为构建过程的一部分来生成用于生产的精简代码:
"devDependencies": { "webpack": "^5.96.1", "webpack-cli": "^5.1.4" }
要启用代码精简,请添加包含以下代码片段的 webpack.config.js 文件。将模式设置为生产告诉 webpack 应用优化,例如修改:
const path = require('path'); module.exports = { mode: 'production', // Enables optimizations like minification and tree-shaking entry: './src/index.js', // Specifies the entry point of your application output: { path: path.resolve(__dirname, 'dist'),// Defines the output directory for bundled files filename: 'bundle.js',// Specifies the name of the bundled file }, };
现在运行 npx webpack 来捆绑并缩小您的代码。生成的 dist/bundle.js 文件的内容如下所示。缩小模糊变量和函数名称,并删除不必要的字符,如空格、注释和未使用的代码,使输出文件更小,加载速度更快:
(()=>{"use strict";const t={};let e=0;const n=document.createElement("button"),o=document.getElementById("previous"),u=document.getElementById("current"),r=document.getElementById("total");n.innerText="Click me",document.body.appendChild(n),n.addEventListener("click",(()=>{var n,c;e+=1,n=e,c=e,t.currentCount=n,t.previousCount=c,t.totalCount=t.totalCount||0+t.currentCount,o.innerText=t.previousCount,u.innerText=t.currentCount,r.innerText=t.total()}))})();
接下来,更新 index.html 文件以引用捆绑的输出,确保您的应用程序使用缩小的代码:
<<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Web Debugging Example</title> <link rel="stylesheet" href="styles.css"> </head> <body> <h1>Web Debug App</h1> <p>Check console for bug</p> <table> <thead> <tr> <th>Previous count</th> <th>Current count</th> <th>Total count</th> </tr> </thead> <tbody> <tr> <td> <p>Finally, run the app and check the console after clicking the button. To preview the app locally, you can use the Live Server extension in VS Code:</p> <p><img src="https://img.php.cn/upload/article/000/000/000/173705233279872.png" alt="app error using minified code" loading="lazy" style="max-width:90%" style="max-width:90%"></p> <p><img src="https://img.php.cn/upload/article/000/000/000/173705233320770.png" alt="Bundled source file" loading="lazy" style="max-width:90%" style="max-width:90%"></p> <p>The error in the console, t.total is not a function, is difficult to interpret. Clicking on the file in the console does not help pinpoint the issue due to the compact and obfuscated nature of minified code. Identifying the root cause of such an error in a large codebase can be frustrating and time-consuming, as the minified code obscures the original logic and context.</p> <h2> 8 JavaScript debugging strategies for web apps </h2> <p>Let’s demonstrate eight methods to help make JavaScript debugging a bit easier:</p> <h3> 1. Source maps </h3> <p>Source maps are files that map your minified code back to the original source code. They make debugging easier and help investigate issues in production. The file names of source maps end with .map.</p> <p>To generate source maps using webpack, update the webpack.config.js file as follows:</p> <p>The devtool: 'source-map' or devtool: 'eval-source-map' line tells webpack to generate an external .map file which maps the minified code back to your original source code. The source map file URL is also added to the minified code in the bundle.js file.</p> <p>Now run npx webpack. The .map file will generate alongside your minified bundle. Serve the application using a local server, and open it in an Incognito browser window. This prevents browser extensions and cached files from interfering with your debugging process.</p> <p>With source maps generated, the following observations are made:</p> <ol> <li> The error is linked to the counter.js file, which is the original source code</li> <li> The source map, bundle.js.map is successfully fetched and is visible under the <strong>Developer resources</strong> tab</li> <li> In the <strong>Sources</strong> tab, the developer tools display the original source code and the problematic line</li> </ol> <p>The exact code and file causing the bug are easy to identify using source maps:</p> <p><img src="https://img.php.cn/upload/article/000/000/000/173705233514189.png" alt="app error from source maps" loading="lazy" style="max-width:90%" style="max-width:90%"></p> <p><img src="https://img.php.cn/upload/article/000/000/000/173705233621716.png" alt="mapped source code javascript debugging" loading="lazy" style="max-width:90%" style="max-width:90%"></p> <p>With the clear error above, we are able to fix the error and access the correct property on countCache.</p> <p>Our guide on how to use Chrome DevTools should provide a great start. To open the <strong>Developer resources</strong> tab, click on the <strong>More</strong> icon, then <strong>More tools</strong> then <strong>Developer resources</strong>. This tab allows you to view the source map load status and even load source maps manually:</p> <p><img src="https://img.php.cn/upload/article/000/000/000/173705233875017.png" alt="accessing developer resources tab javascript debugging" loading="lazy" style="max-width:90%" style="max-width:90%"></p> <p>The code snippet below fixes the bug on the console. Update your code, then run npx webpack to compile the changes. Once completed, serve the application and view the updated output in the table:<br> </p> <pre class="brush:php;toolbar:false">totalElement.innerText = countCache.totalCount;
单击该按钮当前会更新表中的先前计数、当前计数和总计。前一个计数应该返回计数的前一个值,而总计数则返回所有计数值的总和。目前,之前的计数显示当前计数,而总计数停留在 1。
在下一节中,我们将探索其他 JavaScript 调试技术,例如使用断点和单步执行代码,以识别并修复此问题:
断点允许您在特定行暂停代码的执行,帮助您检查变量、计算表达式并理解代码流。根据您的目标,您可以使用不同的断点。例如:
在我们的示例应用程序中,我们将在incrementCounter 函数上应用一个断点。在 Sources 面板上,打开 counter.js 文件并单击第六行左侧。这会在计数增加后设置代码行断点:
我们将在第五行设置另一个断点并编辑它。要编辑断点,我们将右键单击突出显示的部分,然后单击 编辑断点:
我们将断点类型设置为Logpoint,然后输入要记录到控制台的消息:
通过单击按钮,我们的应用程序会在代码行断点处暂停,并从 Logpoint 集在控制台上打印调试日志:
从图像中我们可以看到以下部分:
有了这个,我们可以进一步调试我们的应用程序。
范围面板对于JavaScript调试非常有效,因为它允许您查看原始源中的变量:
我们可以看到以下范围变量:
从范围面板和日志点断点,我们可以看到当前计数为1,而增加之前的计数为0。因此,我们需要将增量之前的计数存储为先前的计数。
单步执行代码涉及在 JavaScript 调试期间以不同方式浏览程序:
您可以使用调试控件来单步执行代码。 Step 控件使您能够一次运行一行代码。单击步骤将执行第六行并移至第七行。注意 previousCount 的值在范围内如何变化:
Step over 控件允许您执行函数而无需逐行执行:
Step into 控件允许您进入函数。在函数中,您可以逐行单步执行代码或 Step out 函数,如下所示。跳出该函数将完成剩余行的执行:
为了解决我们的问题,我们将更新代码,如下所示。现在可以正确显示表格上之前的计数:
export const countCache = { previousCount: 0, currentCount: 0, totalCount: 0 } export function updateCache(currentCount, previousCount) { countCache.currentCount = currentCount; countCache.previousCount = previousCount; c ountCache.totalCount = countCache.totalCount + countCache.currentCount; }
调用堆栈显示导致代码中当前点的函数调用顺序。
如图所示在 counterCache.js 文件中添加一个新断点,然后单击 按钮。观察调用堆栈面板:
当应用程序执行 counterCache.js 的第六行时,会进行三个函数调用。要观察堆栈中任何函数的流程,您可以使用重新启动框架重新启动它们的执行,如下所示:
调试时,您可能希望在工作流程中忽略某些脚本。这有助于跳过库或代码生成器中代码的复杂性。在我们的例子中,我们希望在调试时忽略 counter.js 脚本。
在页面选项卡上,右键单击要忽略的文件,并将脚本添加到忽略列表中:
运行应用程序并在断点处暂停,我们可以看到调用堆栈上的incrementCounter函数现在被忽略。您可以隐藏或显示忽略的帧:
您可以在页面选项卡中对文件进行分组,以便于导航,如下图所示:
监视表达式可让您在代码执行时跟踪特定变量或表达式,帮助您实时监控变化。您可以添加 countCache 等表达式来在单步执行代码时监视值:
要尝试修复总计数的错误,您可以在控制台上运行代码片段以了解逻辑错误。当调试在控制台上重复运行的代码时,可以使用 Snippets.
在 Snippets 选项卡上,添加示例调试脚本,保存脚本,然后单击 Enter 运行脚本:
您可以观察到需要重新排列有错误的表达式来解决问题:
export const countCache = { previousCount: 0, currentCount: 0, totalCount: 0 } export function updateCache(currentCount, previousCount) { countCache.currentCount = currentCount; countCache.previousCount = previousCount; c ountCache.totalCount = countCache.totalCount + countCache.currentCount; }
您可以探索有关调试 Web 应用程序的其他资源,例如这篇关于使用 React DevTools 调试 React 应用程序的文章,它提供了调试基于 React 的应用程序的宝贵见解。此外,本关于使用 Chrome DevTools 调试 Node.js 的指南提供了使用观察器和其他高级 DevTools 功能调试服务器端 JavaScript 的技巧。这些资源可以补充此处讨论的技术,并拓宽您对调试 Web 应用程序的理解。
本教程探讨了使用源映射和 Chrome DevTools 调试精简代码。通过生成源映射,我们将缩小的代码映射回其原始源,从而更轻松地调试我们的 Web 应用程序。 Chrome DevTools 通过断点、单步执行代码、监视表达式等方法进一步增强了 JavaScript 调试过程。
使用这些工具,开发人员可以有效地调试和优化他们的应用程序,即使在处理复杂、精简的代码库时也是如此。该项目的完整代码可以在 GitHub 上找到。
NPM:
import { updateCache } from './counterCache.js'; let count = 0; export function incrementCounter() { count += 1; const previousCount = count; updateCache(count, previousCount); }
脚本标签:
import { incrementCounter } from './counter'; import { countCache } from './counterCache'; const button = document.createElement('button'); const previousElement = document.getElementById('previous'); const currentElement = document.getElementById('current'); const totalElement = document.getElementById('total'); button.innerText = 'Click me'; document.body.appendChild(button); button.addEventListener('click', () => { incrementCounter(); previousElement.innerText = countCache.previousCount; currentElement.innerText = countCache.currentCount; totalElement.innerText = countCache.total(); });
3.(可选)安装插件以与您的堆栈进行更深入的集成:
现在就开始。
以上是如何掌握 Web 应用程序的 JavaScript 调试的详细内容。更多信息请关注PHP中文网其他相关文章!