发布于

js异常处理

Authors
  • avatar
    Name
    田中原
    Twitter

前端异常处理简介

错误类型

每当运行发生错误时,会抛出一个错误对象。 每种错误都有对应的错误类型,而当错误发生的时候就会抛出相应的错误对象。

  • Error:错误的基础对象,其他错误都继承自该类型
  • EvalError:Eval函数没有正确执行时的错误
  • RangeError:当一个值不在有效范围之内时的错误
  • ReferenceError:引用一个未被定义的变量时的错误
  • SyntaxError:解析代码时语法不正确的错误
  • TypeError:值的类型非预期类型时的错误
  • URIError:使用全局URI处理函数时参数不正确的错误
  • AggregateError:当多个错误需要包装在一个错误中时,表示一个错误(实验中的功能)

Error

错误的基础对象,其他错误都继承自该类型

  • message:可选,错误描述信息
  • fileName:可选,调用Error构造函数代码所在的文件名字(这个参数不是标准参数)
  • lineNumber:可选,调用Error构造函数代码所在的文件行号(这个参数不是标准参数)
const error1 = new Error('错误error1')
console.log(error1.message) // 错误error1

EvalError

Eval函数没有正确执行时的错误。此异常不再会被抛出,但是EvalError对象仍然保持兼容性

  • message:可选,错误描述信息
  • fileName:可选,调用Error构造函数代码所在的文件名字(这个参数不是标准参数)
  • lineNumber:可选,调用Error构造函数代码所在的文件行号(这个参数不是标准参数)

RangeError

当一个值不在有效范围之内时的错误

  • message:可选,错误描述信息
  • fileName:可选,调用Error构造函数代码所在的文件名字(这个参数不是标准参数)
  • lineNumber:可选,调用Error构造函数代码所在的文件行号(这个参数不是标准参数)
// 数组长度为负数
new Array(-1) // Uncaught RangeError: Invalid array length

// 使用Number对象的方法时,传入的参数超出了范围
// 参数超出范围
;(66.6).toExponential(101) // Uncaught RangeError: toExponential() argument must be between 0 and 100
;(66.6).toFixed(101) // Uncaught RangeError: toFixed() digits argument must be between 0 and 100
;(66.6).toPrecision(101) // Uncaught RangeError: toPrecision() argument must be between 1 and 100

// 手动抛出错误
new RangeError('RangeError') // RangeError: RangeError

ReferenceError

引用一个未被定义的变量时的错误

  • message:可选,错误描述信息
  • fileName:可选,调用Error构造函数代码所在的文件名字(这个参数不是标准参数)
  • lineNumber:可选,调用Error构造函数代码所在的文件行号(这个参数不是标准参数)
let a = b // Uncaught ReferenceError: b is not defined

// 把一个值分配给无法分配的对象
function abc() {}
// 对函数运行结果进行赋值
abc() = 1 // Uncaught ReferenceError: Invalid left-hand side in assignment

// 手动抛出错误
new ReferenceError('ReferenceError') // ReferenceError: ReferenceError

SyntaxError

解析代码时语法不正确的错误

  • message:可选,错误描述信息
  • fileName:可选,调用Error构造函数代码所在的文件名字(这个参数不是标准参数)
  • lineNumber:可选,调用Error构造函数代码所在的文件行号(这个参数不是标准参数)
// 变量声明时错误
let 777 // Uncaught SyntaxError: Unexpected number

// 调用函数时缺少括号
console.log(123 // Uncaught SyntaxError: missing ) after argument list

// 手动抛出错误
new SyntaxError('SyntaxError') // SyntaxError: SyntaxError

TypeError

值的类型非预期类型时的错误

  • message:可选,错误描述信息
  • fileName:可选,调用Error构造函数代码所在的文件名字(这个参数不是标准参数)
  • lineNumber:可选,调用Error构造函数代码所在的文件行号(这个参数不是标准参数)
// 变量声明时错误
let a = 123
a.shift() // Uncaught TypeError: a.shift is not a function

// 手动抛出错误
new TypeError('TypeError') // TypeError: TypeError

URIError

使用全局URI处理函数时参数不正确的错误

  • message:可选,错误描述信息
  • fileName:可选,调用Error构造函数代码所在的文件名字(这个参数不是标准参数)
  • lineNumber:可选,调用Error构造函数代码所在的文件行号(这个参数不是标准参数)
decodeURI('%') // Uncaught URIError: URI malformed

// 手动抛出错误
new URIError('URIError') // URIError: URIError

AggregateError

当多个错误需要包装在一个错误中时,表示一个错误(实验中的功能)

  • errors:可选,错误对象数组
  • message:可选,错误的提示信息
let p1 = Promise.reject(new Error('p1 error'))
let p2 = Promise.reject(new Error('p2 error'))
let p3 = Promise.reject(new Error('p3 error'))
Promise.any([p1, p2, p3]).catch((e) => {
  console.log(e.message) // All promises were rejected
  console.log(e.name) // AggregateError
  console.log(e.errors[0].message) // p1 error
  console.log(e.errors[1].message) // p2 error
  console.log(e.errors[2].message) // p3 error
})

// 手动抛出错误
try {
  throw new AggregateError(
    [new Error('AggregateError1'), new Error('AggregateError2')],
    'One AggregateError'
  )
} catch (e) {
  console.log(e.message) // One AggregateError
  console.log(e.name) // AggregateError
  console.log(e.errors[0].message) // AggregateError1
  console.log(e.errors[1].message) // AggregateError2
}

异常捕获

try-catch

当不确定某段代码是否会出错时,可以将这段代码放入try代码块中,报错时在catch中进行处理

捕获同步异常

try {
  throw new Error('error1')
} catch (e) {
  console.log(`捕获到异常信息:${e}`)
}
// 捕获到异常信息:Error: error1

不能用于捕获异步异常

try {
  setTimeout(() => {
    throw new Error('error1')
  }, 1000)
} catch (e) {
  console.log(`捕获到异常信息:${e}`)
}
// Uncaught Error: error1

不能用于捕获JavaScript语法错误,手动抛出的语法错误可以捕获

try {
    let a = ;
} catch (e) {
    console.log(`捕获到异常信息:${e}`)
}
// Uncaught SyntaxError: Unexpected token ';'

try {
    throw new SyntaxError('error1')
} catch (e) {
    console.log(`捕获到异常信息:${e}`)
}
// 捕获到异常信息:SyntaxError: error1

Promise catch

Promise中的异常不会被try-catch和window.onerror捕获

捕获同步异常

new Promise((resolve, reject) => {
  throw new Error('error1')
}).catch((e) => {
  console.log(`捕获到异常信息:${e}`)
})
// 捕获到异常信息:Error: error1

不能用于捕获异步异常

new Promise((resolve, reject) => {
  setTimeout(() => {
    throw new Error('error1')
  }, 1000)
}).catch((e) => {
  console.log(`捕获到异常信息:${e}`)
})
// Uncaught Error: error1

不能用于捕获JavaScript语法错误,手动抛出的语法错误可以捕获

new Promise((resolve, reject) => {
    let a = ;
    resolve(a)
}).catch(e => {
    console.log(`捕获到异常信息:${e}`)
})
// Uncaught SyntaxError: Unexpected token ';'

new Promise((resolve, reject) => {
    throw new SyntaxError('error1')
    resolve()
}).catch(e => {
    console.log(`捕获到异常信息:${e}`)
})
// 捕获到异常信息:SyntaxError: error1

Vue errorHandler

指定组件的渲染和观察期间未捕获错误的处理函数。这个处理函数被调用时,可获取错误信息和 Vue 实例。

Vue.config.errorHandler = function (err, vm, info) {
  // handle error
  // `info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子
  // 只在 2.2.0+ 可用
}
  • 从 2.2.0 起,这个钩子也会捕获组件生命周期钩子里的错误。同样的,当这个钩子是 undefined 时,被捕获的错误会通过 console.error 输出而避免应用崩溃。
  • 从 2.4.0 起,这个钩子也会捕获 Vue 自定义事件处理函数内部的错误了。
  • 从 2.6.0 起,这个钩子也会捕获 v-on DOM 监听器内部抛出的错误。另外,如果任何被覆盖的钩子或处理函数返回一个 Promise 链 (例如 async 函数),则来自其 Promise 链的错误也会被处理。

window.onerror

当JavaScript运行时错误(包括语法错误)发生时,window会触发一个ErrorEvent接口的error事件,并执行window.onerror()。若该函数返回true,则阻止执行默认事件处理函数,控制台不会显示默认的报错信息。

  • message:错误信息(字符串)
  • source:发生错误的脚本URL(字符串)
  • lineno:发生错误的行号(数字)
  • colno:发生错误的列号(数字)
  • error:Error对象(对象)

捕获同步异常

window.onerror = function (message, source, lineno, colno, error) {
  console.log('捕获到异常信息:', { message, source, lineno, colno, error })
}

throw new Error('error1')
/* 
捕获到异常信息: 
{
    message: "Uncaught Error: error1",
    source: "file:///D:/1.html",
    lineno: 15,
    colno: 11,
    error: Error: error1
}
*/
// Uncaught Error: error1

捕获异步异常

window.onerror = function (message, source, lineno, colno, error) {
  console.log('window.onerror 捕获到异常信息:', { message, source, lineno, colno, error })
}

new Promise((resolve, reject) => {
  setTimeout(() => {
    throw new Error('error1')
  }, 1000)
  resolve()
}).catch((e) => {
  console.log(`Promise catch 捕获到异常信息:${e}`)
})

/* 
window.onerror 捕获到异常信息:
{
    message: "Uncaught Error: error1",
    source: "file:///D:/1.html",
    lineno: 17,
    colno: 15,
    error: Error: error1
}
*/
// Uncaught Error: error1

不能用于捕获JavaScript语法错误,手动抛出的语法错误可以捕获

window.onerror = function (message, source, lineno, colno, error) {
    console.log('window.onerror 捕获到异常信息:', {message, source, lineno, colno, error})
}

let a = ;
// Uncaught SyntaxError: Unexpected token ';'

throw new SyntaxError('error1')

/*
window.onerror 捕获到异常信息:
{
    message: "Uncaught SyntaxError: error1",
    source: "file:///D:/1.html",
    lineno: 16,
    colno: 7,
    error: SyntaxError: error1
}
*/
// Uncaught SyntaxError: error1

window.addEventListener('error', error => )

与window.onerror功能类型,事件回调函数的参数不同,不能阻止执行默认事件处理函数,控制台会显示默认的报错信息。

  • type:事件类型(字符串)
  • listener:监听的事件类型触发时处理事件的函数(函数)
  • useCapture:可选,默认值为false,在冒泡阶段处理事件;为true时,在捕获阶段处理事件(布尔值)

捕获同步异常

window.addEventListener(
  'error',
  (error) => {
    console.log(`window.addEventListener 捕获到异常信息:${error}`)
  },
  true
)

throw new Error('error1')
// window.addEventListener 捕获到异常信息:[object ErrorEvent]
// Uncaught Error: error1

捕获异步异常

window.addEventListener(
  'error',
  (error) => {
    console.log(`window.addEventListener 捕获到异常信息:${error}`)
  },
  true
)

new Promise((resolve, reject) => {
  setTimeout(() => {
    throw new Error('error1')
  }, 1000)
  resolve()
}).catch((e) => {
  console.log(`Promise catch 捕获到异常信息:${e}`)
})
// window.addEventListener 捕获到异常信息:[object ErrorEvent]
// Uncaught Error: error1

不能用于捕获JavaScript语法错误,手动抛出的语法错误可以捕获

window.addEventListener('error', error => {
    console.log(`window.addEventListener 捕获到异常信息:${error}`)
}, true)

let a = ;
// Uncaught SyntaxError: Unexpected token ';'

throw new SyntaxError('error1')
// window.addEventListener 捕获到异常信息:[object ErrorEvent]
// Uncaught SyntaxError: error1

资源加载异常

window.addEventListener('error', error => )

<script>
  window.addEventListener(
    'error',
    (error) => {
      console.log(`window.addEventListener 捕获到异常信息:${error}`)
    },
    true
  )
</script>

<link rel="stylesheet" href="http://localhost/test.css" />
<img src="http://localhost/test.png" />
<script src="http://localhost/test.js"></script>
<!-- GET http://localhost/test.css net::ERR_CONNECTION_REFUSED -->
<!-- window.addEventListener 捕获到异常信息:[object Event] -->
<!-- GET http://localhost/test.js net::ERR_CONNECTION_REFUSED -->
<!-- window.addEventListener 捕获到异常信息:[object Event] -->
<!-- GET http://localhost/test.png net::ERR_CONNECTION_REFUSED -->
<!-- window.addEventListener 捕获到异常信息:[object Event] -->