错误处理-复习整理

41 阅读4分钟

错误处理

  1. 错误概述

    • 错误处理是程序设计的一个重要组成部分,javascript中以异常的形式提供了错误处理的功能
    • Error对象有三个属性
      • name:错误类型
      • message:错误描述信息
      • stack:错误的堆栈信息
    • Error对象是所有错误对象的基础对象,其他错误对象都继承自Error对象
  2. 错误类型

    • SyntaxError:语法错误

      • 解释:语法错误是指代码不符合语法规范,导致解析错误
      • 常见的原因:括号不匹配、引号不匹配、语句末尾缺少分号等
      • 列子:
      let age v = 18; // Uncaught SyntaxError: Unexpected identifier
      
    • ReferenceError:引用错误

      • 解释:引用错误是指引用了不存在的变量
      • 常见的原因:试图使用一个不可访问的变量、变量未声明、变量名拼写错误等
      • 列子:
         console.log(a); // Uncaught ReferenceError: a is not defined
      
    • RangeError:范围错误

      • 解释:范围错误是指一个值超出了有效范围
      • 常见的原因:数组长度为负数、Number对象的方法参数超出范围,错误的使用数字方法等
      • 列子:
         let arr = new Array(-1); // Uncaught RangeError: Invalid array length
      
    • TypeError:类型错误

      • 解释:类型错误是指变量或参数不是预期类型时发生的错误
      • 常见的原因:变量不是预期类型、参数不是预期类型、使用了nullundefined的对象等
      • 列子:
         let count = 1
         count(); // Uncaught TypeError: count is not a function
      
    • URIError:URI错误

      • 解释:当使用encodeURI()decodeURI()时,如果URI格式不正确,就会抛出URIError错误
      • 常见的原因:使用encodeURI()decodeURI()时,URI格式不正确
      • 列子:
         decodeURI('%2'); // Uncaught URIError: URI malformed
      
    • EvalErroreval函数执行错误

      • 解释:eval函数执行错误时,会抛出EvalError错误
      • 常见的原因:eval函数参数错误
      • ps:现代javascript引擎已经不会抛出EvalError错误
    • InternalError:内部错误

      • 解释:javascript引擎内部错误时,会抛出InternalError错误
      • 常见的原因:javascript引擎内部错误
      • ps:现代javascript引擎已经不会抛出InternalError错误
  3. 抛出错误 Error对象只有在被抛出时才会成为异常

    • throw语句

      • 语法:throw expression
      • 解释:throw语句抛出一个异常,expression是一个表达式,可以是任何值
      • 列子:
        throw 'Error occurred'; // Uncaught Error occurred
      
    • 异常一旦抛出,就会在程序堆栈中向上冒泡,直到被捕获为止

  4. 同步错误处理

    1. 常规函数的错误处理
    function toUpperCase(str) {
      if (typeof str !== 'string') {
        throw new TypeError('str must be a string');
      }
      return str.toUpperCase();
    }
    
     toUpperCase(4)
    

    同步执行的任务可以通过try...catch语句捕获错误

     try {
       toUpperCase(4)
     } catch (e) {
       console.log(e.message); // str must be a string
     }
    
    1. 生成器函数的错误处理
     function* gen() {
       try {
         yield 1;
       } catch (e) {
         console.log(e.message);
       }
     }
    
     let g = gen();
     g.next();
     g.throw(new Error('出错了!')); // 出错了!
    

    可以将try...catch语句包装在生成器中,也可以在生成器外部捕获错误

     function* gen() {
       yield 1;
     }
    
     let g = gen();
     try {
       g.throw(new Error('出错了!'));
     } catch (e) {
       console.log(e.message); // 出错了!
     }
    
  5. 异步函数的错误处理

    • 定时器错误

       setTimeout(() => {
          throw new Error('出错了!');
       }, 1000);
       //将在1s后抛出错误
       
       // 以下代码是无效的,因为定时器是异步执行的,`try...catch`语句无法捕获错误
       function failAfterOneSecond() {
           setTimeout(() => {
               throw new Error('出错了!');
           }, 1000);
       }
       try{
           failAfterOneSecond()
       }catch(error){
           console.log(error.message) // 出错了!
       }
      
       function _failAfterOneSecond() {
         setTimeout(() => {
             try {
                throw new Error('出错了!');
             } catch (e) {
                console.log(e.message);
             }
         }, 1000);
       }
       // 需要在定时器内部使用`try...catch`语句捕获错误
      
       // 使用Promise处理定时器错误
       function failAfterOneSecond_() {
            return new Promise((resolve, reject) => {
            setTimeout(() => {
                reject(new Error('出错了!'));
            }, 1000);
            });
        }
      
        failAfterOneSecond_()
        .then((result) => {
            console.log(result);
        })
        .catch((error) => {
            console.log(error.message); // 出错了!
        });
      
      • 事件的错误处理
      let emitter = new EventEmitter();
      emitter.on('error', (err) => {
         console.log(err.message);
      });
      emitter.emit('error', new Error('出错了!')); // 出错了!
      
      // 事件的错误处理,需要监听`error`事件
      // 如果不想让程序崩溃,为了正确处理错误,必须将try...catch语句放在回调函数内部
      
      let emitter = new EventEmitter();
      emitter.on('error', (err) => {
       try {
         console.log(err.message);
       } catch (e) {
         console.log('内部错误');
       }
      });
      
      
      • onerror事件的错误处理
       window.onerror = function (message, url, line, column, error) {
         console.log(message); // 出错了!
       };
       throw new Error('出错了!');
      
      • Promise对象的错误处理
      function toUpperCase(str) {
        return new Promise((resolve, reject) => {
          if (typeof str !== 'string') {
            reject(new TypeError('str must be a string'));
          }
          resolve(str.toUpperCase());
        });
      }
      // 对函数的改造,不返回简单的字符串或者异常,而是返回一个Promise对象。分别用Promise.resolve()和Promise.reject()方法,将正确结果和错误结果,作为参数传入resolve和reject方法
      
      toUpperCase(4)
      .then((result) => {
        console.log(result);
      })
      .catch((error) => {
        console.log(error.message);
      }).finally(() => {
        console.log('finally');
      });
      // 任何传递给 then、catch 或 finally 的回调都是由微任务队列异步处理的,是微任务,优先于事件和计时器等宏任务执行
      
  6. 错误处理的最佳实践

    • 不要过度处理异常
    • 避免使用浏览器特定的非标准方法
    • 远程记录异常信息(sentry、WeData、等其他上报库)
    • 错误处理中间件
    • 捕获所有未捕获的异常
    • 使用try...catch语句捕获同步错误

摘抄于

  1. 语雀-前端知识进阶