- 发布于
 
js异常处理
- Authors
 
- Name
 - 田中原
 
前端异常处理简介
错误类型
每当运行发生错误时,会抛出一个错误对象。 每种错误都有对应的错误类型,而当错误发生的时候就会抛出相应的错误对象。
- 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] -->