前端常见的报错类型和规避

283 阅读9分钟

一、大家好、早上好、中午好、晚上好

在当今的互联网时代,前端开发扮演着至关重要的角色。无论是网页应用还是移动应用,前端都是用户直接交互的界面。然而,前端开发过程中常常会遇到各种错误,这些错误不仅影响用户体验,还可能导致数据丢失或安全问题。因此,了解前端常见的报错类型及其规避方法对于每一位前端开发者来说都至关重要。本文旨在通过分析前端开发中的常见错误,并提供有效的解决方案,帮助开发者提升代码质量和用户体验。

二、  概述

在调试前端代码时,我们可能会遇到以下几种错误类型:

语法错误(Syntax Error):当代码不符合编程语言的语法规则时,会发生此类错误。常见的情况包括单词拼写错误、遗漏必要的分号、括号不匹配等。

类型错误(Type Error):这类错误发生在代码尝试使用不适当的数据类型或对不存在的对象进行操作时。例如,试图将非函数类型的变量当作函数调用,或者尝试访问未定义的变量。

引用错误(Reference Error):当代码尝试引用一个不存在的变量或函数时,会出现引用错误。比如使用未声明的变量或调用未定义的函数。

范围错误(Range Error):当代码的操作超出了有效范围时,会产生范围错误。例如,访问超出数组界限的索引或递归调用深度过大。

访问错误(Access Error):这类错误发生在代码试图访问受限制的资源时,如尝试进行跨域资源访问或使用非法的文件路径。

异步错误(Async Error):在执行异步操作时可能出现的错误,比如Promise被拒绝处理或网络请求未能成功完成。

标记错误(Markup Error):在HTML或XML代码中,如果存在不正确的标记或结构问题,就会发生标记错误。例如,遗漏闭合标签或错误使用属性。

网络错误(Network Error):与网络相关的错误,包括请求超时、服务器端错误等情况。

性能错误(Performance Error):当代码执行效率低下,导致程序运行缓慢或资源消耗过多时,会产生性能错误,如频繁的页面重绘或大量内存占用。

安全错误(Security Error):涉及安全问题的错误,如遭受跨站点脚本攻击(XSS)或跨站请求伪造(CSRF)等安全漏洞。

三、  错误规避

(1)语法错误(Syntax Error)

就是一些js语法层面的错误:

  1. 命名规则:

a. 变量名必须以字母(包括英文字母、下划线_、美元符号$)、中文汉字或Unicode字符开头。

const username = 'xiaoming';
const _username = 'xiaoming';
const $username = 'xiaoming';
const 用户名 = ‘xiaoming'; // 不建议

b. 变量名不能以数字开头。

const 1username = 'xiaoming';
// Uncaught SyntaxError: Invalid or unexpected token

image.png

c.  变量名中不能包含空格或特殊字符(如!, @, #, %, ^, &, *, (, ), -, +, =, {, }, [, ], |, , :, ;, ", ', <, >, /, ?)。

const !username = 'xiaoming';
// Uncaught SyntaxError: Unexpected token '!'

image.png

d.  变量名是区分大小写的,这意味着userName和username是两个不同的变量。

const userName = 'xiao';
const username = 'ming';

image.png

e.  关键字或者保留字不能作为变量名:for,while,this等

const class = 'xiaoming';
// Uncaught SyntaxError: Unexpected token 'class'Understand this error

image.png

f.  还有一些粗心导致的问题:少’(‘、少’{‘等

console.log('xiaoming';
// Uncaught SyntaxError: missing ) after argument list
let message = 'This is a string
console.log(message); // 缺少闭合引号

image.png

2.  命名规范:(不会报错)

a.  使用有意义且易于理解的名称,避免使用缩写或难以理解的字符组合。

b.  采用驼峰命名法(camelCase)是一个常见的JavaScript命名约定,即第一个单词的首字母小写,后续单词的首字母大写。

c.  常量通常使用全大写字母命名,单词之间可以用下划线分隔(如MAX_COUNT)。

d.  使用名词来命名变量,因为变量通常是用来存储数据的。

e.  如果变量用于存储函数,可以使用动词开头,表明这是一个动作。

(2)类型错误(Type Error)

类型错误通常发生在执行特定操作时,变量或参数不是期望的数据类型。这个报错应该是很常见的报错

let num = 10;
num.toUpperCase(); // TypeError: num.toUpperCase is not a function
let obj = {};
obj.doSomething(); // TypeError: obj.doSomething is not a function
let str = "xiao";
str.push("ming"); // TypeError: str.push is not a function

image.png

(3)引用错误(Reference Error)

引用错误发生在变量尚未声明或已经声明但没有正确初始化时。这个错误非常常见

console.log(username); // ReferenceError: username is not defined

image.png

(4)范围错误(Range Error)

范围错误发生在数值超出其合法范围时。

new Array(-1); // RangeError: Invalid array length

function factorial(n) {
  if (n === 0) return 1;
  return n * factorial(n - 1);
}
factorial(Infinity); 
// RangeError: Maximum call stack size exceeded

image.png

(5)访问错误(Access Error)

访问错误通常与Web API有关,当尝试访问不允许的资源时发生。

// 尝试读取一个不允许访问的本地文件
fetch('/path/to/forbidden/file'); // DOMException: Failed to fetch

image.png

(6)异步错误(Async Error)

异步错误通常发生在处理异步操作时,例如Promise或async/await。

new Promise((resolve, reject) => {
  reject(new Error("Async error occurred"));
}).then(() => {}).catch(e => console.error(e)); // Error: Async error occurred

image.png

(7)标记错误(Markup Error)

标记错误通常发生在HTML或XML代码中,不严格属于JavaScript错误类型,但可以影响JavaScript代码的执行。

<!-- 缺失闭合标签 -->
<p>This is a paragraph
<div>This is a div</div

(8)网络错误(Network Error)

网络错误通常发生在网络请求无法完成时,例如在尝试加载资源或发送请求时遇到问题。

fetch('https://xxx.com/data')
  .then(response => response.json())
  .catch(error => console.error('Network Error:', error));

image.png

(9)性能错误(Performance Error)

性能错误通常发生在代码执行时间过长或内存使用过多,导致浏览器或系统无法正常工作。

// 创建一个巨大的数组导致内存不足
let hugeArray = new Array(1000000000).fill('data');

image.png

(10)安全错误(Security Error)

安全错误通常发生在尝试执行违反浏览器安全策略的操作时。

// 尝试从HTTPS页面加载HTTP资源
const script = document.createElement('script');
script.src = 'http://insecure.com/script.js';
document.head.appendChild(script);

image.png

浏览器其他报错情况

● Resource Error:资源加载错误

<!-- 假设style.css文件不存在 -->
<link rel="stylesheet" type="text/css" href="style.css">

● Http Error:http请求错误

// http://example.com/xxx-url 这个地址不存在
fetch('http://example.com/xxx-url')
  .then(response => {
    if (!response.ok) {
      throw new Error('HTTP error! status: ' + response.status);
    }
    return response.json();
  })
  .catch(error => console.error('Fetch error:', error));

● XMLHttpRequest cannot load http://你的地址. No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://你的地址’ is therefore not allowed access。这是进行异步请求时,产生跨域。可以在开发时使用开发者环境可以规避跨域

// 假设服务器没有设置Access-Control-Allow-Origin头部
fetch('http://myservice.com/data')
  .then(response => response.json())
  .catch(error => console.error('Cross-Origin Error:', error));

● Illegal break statement 出现了非法语句

function loop() {
  for (let i = 0; i < 5; i++) {
    if (i === 2) {
      break; // 正确使用
    }
    break; // 非法使用,break语句不能在这里出现
  }
}
loop();

● GET file:///::ERR_FILE_NOT_FOUND 找不到引入的.js文件

<!-- 假设script.js文件不存在 -->
<script src="script.js"></script>

● Failed to load resource: the server responded with a status of 404 (Not Found) 文件没有被找到,说明文件引用的路径有问题,或文件损坏

<!-- 假设image.png文件不存在 -->
<img src="image.png" alt="Image not found">

● InvalidCharacterError:无效字符错误,当字符串中包含无效字符时发生,比如在特定的上下文中使用某些控制字符。

// 假设某些环境不允许字符串中包含控制字符
let controlCharString = String.fromCharCode(0x1B); // ESC字符
console.log(controlCharString);

● QuotaExceededError:超出配额错误,当Web存储(如localStorage或IndexedDB)的容量超出限制时发生。

// 假设localStorage已满
localStorage.setItem('key', 'value');

● InvalidStateError:无效状态错误,当DOM对象处于不允许执行某操作的状态时发生。

// 假设尝试在不合适的时机使用XMLHttpRequest对象
let xhr = new XMLHttpRequest();
xhr.abort(); // 立即终止请求
xhr.open('GET', 'http://example.com/data', true);
xhr.send();

四、错误捕获

1、try/catch

try {
  // 执行的代码
} catch (error) {
  // 发生错误时执行的代码
  // 'error' 是一个包含了错误信息的对象
} finally {
  // 无论是否出现错误都会执行的代码
  // 这个块是可选的
}

注意点:

1.  异步错误:对于异步代码(例如,使用 setTimeout 或 Promise),try...catch 无法直接捕获异步函数中抛出的错误。需要在该异步函数内部使用 try...catch,或者在调用异步函数的地方处理 .catch()。

2.  能捕获常规的运行时错误,语法错误不能捕获:这些错误在代码解析阶段就发生,因此在执行之前就抛出,无法在运行时通过 try...catch 捕获。

3.  事件处理器错误:在事件处理器内部发生的错误不会被外部 try...catch 捕获。需要在事件处理器内部使用 try...catch。

4.  资源加载错误、网络错误也不能捕获。

2、window.onerror

全局错误处理可以通过监听 window.onerror 事件来实现,它能够捕获大多数未被 try...catch 捕获的错误。

window.onerror = function(message, source, lineno, colno, error) {
  // 处理错误
  console.error("捕获到错误: ", message, " 在 ", source, lineno, colno);
};

3、window.addEventListener(‘error’, fn)

与 window.onerror 类似,但使用 addEventListener 允许你添加多个错误处理程序。

window.addEventListener('error', function(event) {
  // 处理错误
  console.error("捕获到错误: ", event.message);
});

4、Promise异步错误

这个错误我被坑过,就是你的Promise 的 .catch() 方法我没有定义导致错误无法定位。

那如果.catch()方法未定义,那改怎么捕获这个错误呢?

我们可以使用unhandledrejection 事件来捕获:

window.addEventListener('unhandledrejection', function(event) {
  // 处理未处理的 Promise 拒绝
  console.error("未处理的 Promise 拒绝: ", event.reason);
});

五、前端框架错误捕获

1、  Vue

在 Vue 中,可以使用全局配置来捕获错误,或者使用生命周期钩子和错误处理指令。

Vue.config.errorHandler = function (err, vm, info) {
  // 处理错误
  console.error('Error:', err);
  console.info('Info:', info);
};

2、  React

在 React 中,可以使用错误边界(Error Boundaries)来捕获组件树中子组件发生的错误。

创建一个错误边界组件,它可以捕获其子组件树中发生的 JavaScript 错误,并记录这些错误,同时展示一个备用的 UI。

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }
  componentDidCatch(error, errorInfo) {
    console.error('Caught an error:', error, errorInfo);
  }
  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}

3、  Angular

在 Angular 中,可以使用全局的异常处理器,通过在应用程序模块中提供全局的异常处理服务,可以捕获应用中的所有异常。

import { ErrorHandler, Injectable } from '@angular/core';

@Injectable()
export class GlobalErrorHandler implements ErrorHandler {
  handleError(error: any): void {
    console.error('Error from global error handler', error);
  }
}

// 在@NgModule装饰器中替换默认ErrorHandler
imports: [
  // ...
],
providers: [
  { provide: ErrorHandler, useClass: GlobalErrorHandler }
]

志哥我想说

以上是我在每周技术分享会给组员分享的内容,如果你正巧也需要分享,并且没有内容可分享时,可以点赞、收藏,下次分享不迷路~