LoginSignup
7
6

More than 5 years have passed since last update.

第一引数にエラーが渡されるコールバック関数からエラー処理を退避させる

Last updated at Posted at 2014-04-19
はじめに

この記事はコールバック地獄からの脱却を狙った記事ではありません

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)
}
7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6