Node.js下自定義錯誤類型
在JavaScript裏面,運行過程中的錯誤的類型總是被人忽略,這篇教程主要從三個方面來介紹如何在Node.js下自定義錯誤類型。
- 爲什麼要使用錯誤對象。
- 怎麼創建自定義錯誤對象。
- 一些自定義錯誤對象的例子。
爲什麼要使用錯誤對象
一般來說,很少人會考慮如何處理應用產生的錯誤的策略,調試的過程中,簡單地利用console.log('error')定位錯誤,基本夠用了,通過留下這些調試信息,能夠爲我們以後的調試過程中升了不少時間,提高了維護性。所以錯誤提示非常重要。同時,也會帶來一些比較糟糕用法。
糟糕的字符串錯誤提示
Guillermo Rauch 曾經寫了一篇優秀的文章解釋爲什麼最好不要用字符串作爲錯誤調信息,以下是一種常見的錯誤處理方式
if (id < 0) return 'id must be positive'
直接返回錯誤字符串信息,雖然很簡單,但是項目大了,就不好維護了,會產生以下這幾個問題。
很難知道錯誤在哪裏發生的?
除非你的打印字符串裏面,包含了文件和代碼的行數,要不然,你根本不知道錯誤在哪裏發生的。
不能處理不同類型的錯誤
如果全部都是使用字符串作爲錯誤提示,在運行的過程中,很難針對不同類型的錯誤進行不同的處理,有時候我們需要針對不同的錯誤進行不同類型的處理,如提交表單信息錯誤,數據庫類型錯誤等。
系統錯誤對象
利用系統自帶的錯誤類型來代替純字符串的錯誤提示
if (id < 0) return new Error('id must be positive')
儘管看上去只是多了一點小步驟,但實際上卻帶了了很多好處。
獲取錯誤在哪裏發生
如果用了錯誤,對象會產生堆棧屬性,通過執行文件,通過行號,查找到出錯的地方。
console.log(error.stack)
Error: An error occurred
at Object.<anonymous>(/Users/ds/main.js:1:73)
at Module._compile (module.js:441:26)
at Object..js (module.js:459:10)
at Module.load (module.js:348:31)
at Function._load (module.js:308:12)
at Array.0 (module.js:479:10)
at EventEmitter._tickCallback (node.js:192:40)
獲取錯誤類型
可以通過Instanceof 來檢查錯誤類型,根據類型進行不同的處理
if (err instanceof DatabaseError) { /* do this */ }
if (err instanceof AuthenticationError) { /* do that */ }
如何創建一個自定義的錯誤對象
通過對錯誤對象的繼承與複寫的手段,創建一個自定義的錯誤對象。
抽象錯誤對象類型
創建一個抽象的錯誤類基類
var util = require('util')
var AbstractError = function (msg, constr) {
Error.captureStackTrace(this, constr || this)
this.message = msg || 'Error'
}
util.inherits(AbstractError, Error)
AbstractError.prototype.name = 'Abstract Error'
定義數據庫錯誤對象
利用上述創建的抽象錯誤類型,擴展到其他自定義錯誤類型當中
var DatabaseError = function (msg) {
DatabaseError.super_.call(this, msg, this.constructor)
}
util.inherits(DatabaseError, AbstractError)
DatabaseError.prototype.message = 'Database Error'
錯誤類型部署到應用當中,下例
function getUserById(id, callback) {
if (!id) {
return callback(new Error('Id is required'))
}
// Let’s pretend our database breaks if we try to
// find a user with an id higher than 10
if (id > 10) {
return callback(new DatabaseError(Id can't be higher ↵ than 10))
}
callback(null, { name: 'Harry Goldfarb' })
}
function onGetUserById(err, resp) {
if (err) {
return console.log(err.toString())
}
console.log('Success:', resp.name)
}
getUserById(1, onGetUserById) // Harry Goldfarb
getUserById(null, onGetUserById) // Error: Id is required
getUserById(53, onGetUserById)
// Database Error: Id can't be higher than 10
效果出來了,我們的getUserById 的方法,現在可以返回兩種不同類型的錯誤,一個是原生的錯誤類型,一個是自定義的數據庫錯誤類型databaseerror,如果我們調用toString,我們可以看到錯誤類型的返回
// start our script in production mode
$ NODE_ENV=production node main.js
function onGetUserById(err, resp) {
if (err) {
if (err instanceof DatabaseError &&
process.env.NODE_ENV != 'production') {
return console.log(err)
}
return console.log('Sorry there was an error')
}
console.log(resp.name)
}
根據不同錯誤類型進行不同情況的處理
複用錯誤類型
我們不需要每次都重新定義我們的自定義錯誤在每一個文件裏面,我們只需要創建一個文件,調用一個很重要的node.js方法require就足夠了
// in ApplicationErrors.js
var util = require('util')
var AbstractError = function (msg, constr) {
Error.captureStackTrace(this, constr || this)
this.message = msg || 'Error'
}
util.inherits(AbstractError, Error)
AbstractError.prototype.name = 'Abstract Error'
var DatabaseError = function (msg) {
DatabaseError.super_.call(this, msg, this.constructor)
}
util.inherits(DatabaseError, AbstractError)
DatabaseError.prototype.name = 'Database Error'
module.exports = {
Database: DatabaseError
}
// in main.js
var ApplicationError = require('./ApplicationErrors')
function getUserById(id, callback) {
if (!id) {
return callback(new Error('Id is required'))
}
if (id > 10) {
return callback(new ApplicationError.Database('Id cant ↵ be higher than 10'))
}
callback(null, { name: 'Harry Goldfarb' })
}
由此可見,我們只需要定義一次,其他地方也能使用錯誤對象類型。