likes
comments
collection
share

前端基础知识-错误调试和处理

作者站长头像
站长
· 阅读数 6

前言

本系列记录和整理前端的基础知识,希望通过系统性地学习来巩固自己对前端的理解。以《高级程序设计》第 4 版(红宝书),作为学习主体,结合自己工作中遇到的实际案例来了解、理解文中的基础知识点。接下来就一起来看看吧

调试技术

常用技巧

罗列一些,自己在平时开发过程中经常使用的调试技巧,有效的提高自己的开发效率。

  • 代码块的使用

前端基础知识-错误调试和处理

  • 快速获取 DOM 节点引用

前端基础知识-错误调试和处理

  • show changes 查看 css 改动,有时为了方便,我们会选择直接在浏览器,当调试完后如何查看我们改了哪些样式呢?
    • commond + shift + p 唤起面板, 输入 show changes 查看改动 diff

前端基础知识-错误调试和处理

前端基础知识-错误调试和处理

Debug JavaScript

单步全文调试代码

用的最多的还是使用 Debug JavaScript。可以打开 debug demo

前端基础知识-错误调试和处理

来看下如何给 js 文件设置断点。当我们点击按钮时会执行 onClick 函数

function onClick() {
  // 执行函数1
  if (inputsAreEmpty()) {
    label.textContent = 'Error: one or both inputs are empty.';
    return;
  }
  // 执行函数2
  updateLabel();
}

首先我们将断点设置在 15行。此处是函数执行的入口处。我们可以通过操作这五个按钮来进一步 Debug 代码 前端基础知识-错误调试和处理

  1. 运行代码直到下一个断点,如果后续无断点则一直运行到结束。
  2. 单步执行到下一个函数执行前。这里的下一个函数指的是同一作用域中。比如 onClick 函数中调用了两个函数,如果我们点击 2 按钮,我们应该会跳转到 updateLabel() 这一行。

前端基础知识-错误调试和处理 3. 进入下一个函数。也是针对同一作用域下,下一个要执行的函数是 inputsAreEmpty, 当我们点击 3 会执行到 inputAreEmpty 函数的第一行。 前端基础知识-错误调试和处理

  1. 跳出当前函数。当我们发现当前函数没有我们 Debug 信息,我们需要跳出当前作用域进入父级作用域继续往下 Debug。紧跟第 3 步如果我们想要跳出 inputsAreEmpty 就可以点击按钮 4 。此时直接来到父作用域的下一步。

前端基础知识-错误调试和处理

  1. 如果你想完整地走一遍函数的执行流程,你可以一直点按钮 5。注意如果函数有 return 值的函数,return 值也算一步,有时候会看见在同一行断点停了两次。

前端基础知识-错误调试和处理

前端基础知识-错误调试和处理

检查变量

  • 方式一: 在 Scope 面板中查看当前作用域和作用域链上的变量

前端基础知识-错误调试和处理

  • 方式二: 在 watch 面板输入要监听的变量

前端基础知识-错误调试和处理

  • 方式三: 直接在 console 中输入当前作用域可访问的变量。此方法在变量比较多的时候比较有用,也可以自行根据当前作用域变量进行一些运算。

前端基础知识-错误调试和处理

  • 查看调用栈:

前端基础知识-错误调试和处理

前端基础知识-错误调试和处理

  1. 点击调用栈可以查看其作用域的变量
  2. 当一个方法有多个入口共同调用,可以通过调用栈来定位到触发函数的起源在哪,有利于我们判断。

修复

当我们发现 bug 可以直接在文件中修改,不需要刷新,在此进行点击事件进行结果验证。如果符合预期后将代码更新同步到自己本地的代码中。

错误

通过调试我们可以快速定位到错误位置,接下来我们来看看常见的有哪些错误,如何进行处理,以及如何抛出错。

错误类型

代码执行过程中会发生各种类型的错误。每种类型都会对应一个错误发生时抛出的错误对象。ECMA-262定义了以下 8 种错误类型:

  • Error 基类,其他错误类型继承该类型。所有错误类型都共享相同的属性。
  • InternalError 类型。浏览器抛出,如栈溢出。
  • EvalError 类型。使用 eval() 异常抛出。
  • RangeError 类型。数值越界时抛出。
  • ReferenceError 类型。找不到对象时发生。
  • TypeError 类型。主要发生在变量不是预期类型。
        let o = new 10;
        'name' in true;
        Function.prototype.toString.call('name');
    
  • URIError 类型。在使用 encodeURI() 或 decodeURI() 传入格式错误的 URI 时发生。

错误捕获

  • window error 监听运行时报错。在任何错误发生时,无论是否是浏览器生成的,都会触发。
  window.addEventListener('error', (msg,url,lineNo,columnNo,e) => {
    // ...上报错误
  }) 
  • promise reject 未捕获。
  window.addEventListener('unhandledrejection',(event) => {
    // 报错原因,当前路径,报错时间
    const { message,config:{method,url} } = event.reason
    // ...上报错误
  })
  • try catch 捕获同步代码错误
  // 保存原生的 addEventListener 事件
  const originAddEventListener = EventTarget.prototype.addEventListener
  // 重写原生的监听事件
  EventTarget.prototype.addEventListener = (type,listener,options) => {
    const wrappedListenner = (...args) => {
      try {
        return listener.apply(this,args)
      } catch (error) {
        const { name,message } = error
        // ...上报错误
        throw error
      }
    }
    return originAddEventListener.call(this,type,wrappedListenner,options)
  }

抛出错误

throw new Error('something bad happened')
throw new SyntaxError('something bad happened')
throw new TypeError('something bad happened')
throw new RangeError('something bad happened')
throw new ReferenceError('something bad happened')

识别错误

  • 静态代码分析, 推荐使用 TypeScript
  • 类型转换错误, 通常是自动改变某个值的数据类型的操作符造成,如使用 (==) 或 (!=) 。以及 if、for 或 while 中使用非布尔值。
  • 数据类型错误, 进行类型检查保证安全
function getQueryString(url) {
    if(typeof url === 'string') {
        let pos = url.indexOf('?')
        if(pos > -1) {
            return url.substring(pos + 1)
        }
    }
    return '';
}

小结

对于今天复杂的 Web 应用程序而言,js的错误处理和快速定位十分重要。梳理了浏览器的常用的 Debug 方法,一些常出现的错误类型。在平时开发中有意识地去判断是否要进行错误的捕获,以及有效的错误的识别有助于写出更健壮的代码。

参考

《高级程序设计》第 4 版 Chrome Developers