跳到主要内容

错误监控

异常捕获

运行时代码异常,会自动抛出错误,并中断后续代码的执行

// 例子1
let x = y
console.log('aka') // 不会输出

// 例子2
JSON.parse('hello aka')
console.log('aka') // 不会输出

// 例子3
JSON.parse(undefined)
console.log('aka') // 不会输出

我们也可以通过throw手动抛出错误

// 例子4
throw new Error('手动抛出的错误')
console.log('aka') // 不会输出

为了避免代码的异常不会影响后续代码的执行,我们应该使用try...catch捕获异常

// 例子1
try {
let x = y
} catch(err) {
console.log(err)
}
console.log('aka') // 输出

// 例子2
try {
JSON.parse('hello aka')
} catch(err) {
console.log(err)
}
console.log('aka') // 输出

// 例子4
try {
throw new Error('手动抛出的错误')
} catch(err) {
console.log(err)
}
console.log('aka')

以上重点在代码的错误,接下来是诸如文件读取、I/O操作类型的错误

fs.readFile('file', (err, data) => {
if (err) {
console.log(err) // 读取失败时,可输出错误信息以供开发者参考
}
console.log(data) // 读取失败时为undefined
})

即使文件读取失败,fs模块也会帮我们捕获异常,因此后续代码的执行不受影响。

fetch('A')
.then(res => res.json())
.then(data => fetch('b', data))
.then(res => res.json())
.catch(err => console.log(err))

该代码中,无论是fetch失败抛出错误,还是then内部出现代码异常抛出错误,都会让promise的状态变成rejected,此时会把抛出的错误传给末端的catch

而最终形态的异常捕获就是try...catch配合await来捕获promise内部的异常

try {
const data = await fetch()
} catch (e) {
console.log(e)
}

补充1:

let p = new Promise((resolve, reject) => {
throw new Error('error')
console.log(1) // 不输出
})
console.log(2) // 输出

简单来讲,promise内部出现的异常会中断内部后续代码的执行,同时promise的状态变成rejected,等待着外部进行异常的捕获。通常我们会用.catchtry...catch + await来捕获该异常。

补充2:

try...catch捕获捕获异步代码内部的错误,如:

try {
setTimeout(() => {
throw new Error('222')
})
} catch (e) {
console.log(2) // 不输出,因为没有捕获到异常
}

我们可以这样:

async function A() {
try {
await new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('222'))
})
})
} catch (e) {
console.log(e)
}
}

补充3:

也可以使用类似window.onerror的方法来捕获一些资源加载的错误

window.onerror = function(errorMessage, scriptURI, lineNo, columnNo, error) {
console.log('errorMessage: ' + errorMessage); // 异常信息
console.log('scriptURI: ' + scriptURI); // 异常文件路径
console.log('lineNo: ' + lineNo); // 异常行号
console.log('columnNo: ' + columnNo); // 异常列号
console.log('error: ' + error); // 异常堆栈信息
}

内存泄漏

内存泄漏(memory leak),指的是不再使用的内存,却没有被即时的释放。

一个广为流传的错误观点:闭包会造成内存泄漏。

实际上这是十分错误的,之所以这种观点会流传至今,是因为早年的IE浏览器存在垃圾回收的BUG。内存泄漏指的是不再使用的变量没有被回收,可是闭包中的变量是我们需要用到的呀。每一个传播“闭包会造成内存泄漏”这种错误观念的同学都应该被打一顿...只要程序写错了才会造成内存泄漏。

常见内存泄漏

  1. 意外的全局变量

    // 意外的声明了全局的变量,在页面关闭前a变量都不会被回收
    (function A() {
    a = '123'
    })()
  2. 循环引用

  3. 删除DOM时,还存在DOM的引用

    比如,我们给DOM绑定点击事件,之后删除DOM节点。因为还存在引用,所以内存没有被释放。