😵

node.jsで例外処理をまとめようとしたら躓いた

2022/01/26に公開

したいこと

以下のようなコードがあったとする

const test = (a) => {
	if (a == 1) {
		try{
			errorOcc("エラー出してほしい");
		} catch(e) {
			console.log("Error");
			console.error(e);
		}
	} else {
		try{
			errorOcc("こっちもエラー出してほしい");
		} catch(e) {
			console.log("Error");
			console.error(e);
		}
	}
}

こんなふうにtry-catchで多くの行数を占め、読みにくくなる。そこで、

const handleFunc = (method) => {
	try {
		method();
	} catch (e) {
		console.log("Error");
		console.error(e);
	}
}

こんな関数を作って、まとめたい。

まず、書いて動かしてみた(動かないコード)

まず動かないコードです、こんな感じで書けるのではと思いました。

const test = (a) => {
	if (a == 1) {
		handleFunc(errorOcc("エラー出してほしい"));
	} else {
		handleFunc(errorOcc("こっちもエラー出してほしい"));
	}
}

その結果がこちら

Error: こっちもエラー出してほしい
    at errorOcc (/home/akira/Documents/rtGraph/server.js:118:9)
    at sessionCheck (/home/akira/Documents/rtGraph/server.js:128:18)
    at /home/akira/Documents/rtGraph/server.js:89:7
    at Layer.handle [as handle_request] (/home/akira/Documents/rtGraph/node_modules/express/lib/router/layer.js:95:5)
    at next (/home/akira/Documents/rtGraph/node_modules/express/lib/router/route.js:137:13)
    at Route.dispatch (/home/akira/Documents/rtGraph/node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (/home/akira/Documents/rtGraph/node_modules/express/lib/router/layer.js:95:5)
    at /home/akira/Documents/rtGraph/node_modules/express/lib/router/index.js:281:22
    at param (/home/akira/Documents/rtGraph/node_modules/express/lib/router/index.js:360:14)
    at param (/home/akira/Documents/rtGraph/node_modules/express/lib/router/index.js:371:14)

動いてそうなんですが、console.log("Error");が呼ばれていないので、例外処理が通ってないんですね。関数呼び出されてるのに、例外処理が通らないってどういうことだよと思ったのですが、次のように書かないといけないそうです。

修正する(動いたコード)

const test = (a) => {
	if (a == 1) {
		handleFunc(() => {
			errorOcc("エラー出してほしい");
		});
	} else {
		handleFunc(() => {
			errorOcc("こっちもエラー出してほしい");
		});
	}
}

これを動かすと以下のようになります。

Error
[2022-01-26T20:01:59.044] [ERROR] default - Error: こっちもエラー出してほしい
    at errorOcc (/home/akira/Documents/rtGraph/server.js:118:9)
    at /home/akira/Documents/rtGraph/server.js:130:7
    at handlingFunc (/home/akira/Documents/rtGraph/server.js:110:5)
    at sessionCheck (/home/akira/Documents/rtGraph/server.js:129:5)
    at /home/akira/Documents/rtGraph/server.js:89:7
    at Layer.handle [as handle_request] (/home/akira/Documents/rtGraph/node_modules/express/lib/router/layer.js:95:5)
    at next (/home/akira/Documents/rtGraph/node_modules/express/lib/router/route.js:137:13)
    at Route.dispatch (/home/akira/Documents/rtGraph/node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (/home/akira/Documents/rtGraph/node_modules/express/lib/router/layer.js:95:5)
    at /home/akira/Documents/rtGraph/node_modules/express/lib/router/index.js:281:22

npmのlog4jsを使っているので、要らないものも付いていますが、console.log("Error");も呼び出され、無事、例外処理が行えていることが分かりました。

当初のコードでは動かなかった理由

記事を読んだ友人が、当初のコードでは動かない理由を教えてくれました。

const handleFunc = (method) => {
	try {
		method();
	} catch (e) {
		console.log("Error");
		console.error(e);
	}
}

const test = (a) => {
	if (a == 1) {
		handleFunc(errorOcc("errorOccを結果を代入している"));
	} else {
		handleFunc(() => {
			errorOcc("これは関数自体を代入している")
		});
	}
}

test関数の中で呼び出している2つの例でhandleFunc(errorOcc("errorOccを結果を代入している"));の方は、handleFuncerrorOcc("errorOccを結果を代入している")の結果を代入しているので、handleFuncの中で呼び出されているmethod()では結果が表示されるのみなんですね。したがって、例外もここでは発生しないです。一方で、handleFuncに無名関数を挟んでいる場合は、この無名関数自体を代入しているので、handleFuncの中で呼び出されているmethod()は関数になります。つまり、関数を代入したい場合は関数自体(関数オブジェクト)を代入しないといけないということだそうです。

参考

JavaScriptと非同期のエラー処理 / 中野 https://techblog.yahoo.co.jp/programming/javascript_error/ (2022-01-26閲覧)

Discussion