はじめに
この記事はコールバック地獄からの脱却を狙った記事ではありません
if (err) return onError(err) と書くのは不毛に感じる
nodejsライクなコールバック関数(第一引数にエラーを取る関数)を引数として取る関数(parse)を書いたとする。そして実際に parse を使うコードをこんな感じで書いたとする
ex01.js
function onError (err) { console.log(err.stack || err.toString()) }
var reg = /[0-9a-zA-Z._\-]+@[0-9a-zA-Z._\-]+?\.org/g
var x = new XMLHttpRequest
x.addEventListener('load', function () {
parse(x.responseText, reg, function (err, list) {
if (err) return onError(err)
// 正常なケースの処理
some_works(list)
})
})
なんというか、、、parse関数の中で例外処理を別の関数(onError)に渡すというのを明示的に書いているのが面倒くさいというか、何を無駄なことやっているんだろう? という気になる。特にネストが深くなればなるほど無駄感がひどい!
nodejsの世界だとDomain#intercept でエラー処理の部分と正常なケースの処理の部分を分離することができるのでそれを真似てみる
ex02.js
var d = new Domain
d.onError = function (err) { console.log(err.stack || err.toString()) }
var reg = /[0-9a-zA-Z._\-]+@[0-9a-zA-Z._\-]+?\.org/g
var x = new XMLHttpRequest
x.addEventListener('load', function () {
parse(x.responseText, reg, d.intercept(function (list) {
// 正常なケースの処理
some_works(list)
}))
})
もし、parse関数が例外を投げた場合、d.onError に例外が渡されて、d.interceptでラップされたコールバック関数にはエラーが届かない。(parse関数は ex01 も ex02 も同じ)
これだけでも正常ケースな処理の道筋からエラー処理の分岐が消えるので見通しがよくなるので嬉しい。
最後に
nodejs以外でDomain機構を持つライブラリーがあるのか知らないので、お勧めのライブラリー、その他の方法があったら教えてください
domain.js
;(function (global) {
'use strict'
var isBrowser = !! global.self
var isWorker = !! global.WorkerLocation
var isNodeJS = !! global.global
function Domain () {}
Domain.prototype.intercept = function (cb, she) {
var me = this
return function () {
var args = [].slice.apply(arguments)
var err = args.shift()
err ? (typeof me.onError === 'function' && me.onError(err))
: cb.apply(she, args)
}
}
if (isNodeJS) {
module.exports = Domain
} else {
global.Domain = Domain
}
})(this.self || global)
parse.js
// 文字列から正規表現にマッチしたリストを第2引数に渡す: 正常な値として
// マッチしない場合はエラーを第1引数に渡す: エラーケースとして
function parse (str, reg, cb) {
var res, list = []
try {
while (res = reg.exec(str)) {
list.push(res)
}
} catch (err) { return cb(err) }
if (list.length === 0) {
return cb(new Error('string did not match regular.'))
}
cb(null, list)
}