質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.91%

return res.send()とres.send()の違いについて

解決済

回答 5

投稿

  • 評価
  • クリップ 0
  • VIEW 454

__stsh

score 37

app.get('/users/:id', (req, res) => {
  const _id = req.params.id
  User.findById(_id).then((user) => {
    if (!user) {
      return res.status(404).send()
    }
    res.send(user)
  }).catch((e) => {
    res.status(500).send()
  })
})

if文の中でreturnが使われており、if文内の処理を実行させるとres.status(404).send()が実行されますが、これは普通にres.status(404).send()と書くのと何か違いがあるのでしょうか?

意図があってわざわざreturnを加えているとは思うのですが、どのような意図なのか分かりませんでした。

分かる方いらっしゃいましたらぜひご教授ください。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

checkベストアンサー

+4

問題の部分だけを展開します。

function (user) {
  if (!user) {
    return res.status(404).send()
  }
  res.send(user)
}

これはガード節と呼ばれる書き方です。
参考記事: 初心者向け。覚えておきたい 「ガード節」という書き方。 - Qiita

普通に書くとこうなります。

function (user) {
  if (!user) {
    res.status(404).send()
  } else {
    res.send(user)
  }
}

このif-elseは処理が複雑になればなるほどインデントがネストされていき、
非常に読みづらくなってしまいます。
そこで探索を早期に打ち切るのがガード節というテクニックです。


Node.jsのExpress.js系だと思われますが、
Express.jsのres.sendメソッドは2回実行するとエラーになります。
なのでelse側は実行させてはいけません。

ifに入ったものを早期に終了させるreturnが必要不可欠となります。

function (user) {
  if (!user) {
    res.status(404).send()
    return // 返り値なしで処理を打ち切る明示的なreturn
  }
  res.send(user)
}

returnによる返り値は基本的に後で使うと明示した方が良いのは事実ですが、
別に不具合が発生しないとわかっている箇所ならば問題ありません。
今回はUser.findById(_id).then(fn1).catch(fn2)のfn1の部分で実行しますよと記述されていますから、返り値は誰も使って居ないのが一目瞭然ですね。

まぁ、行数が減ると読む時に楽なんで、
私が自分一人のプロジェクトでif文で1行だけの時は{}すら省略出来るのでこんな感じで横着してます。

function (user) {
  if (!user) return res.status(404).send()
  res.send(user)
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/14 12:09

    リーダブルコードが早期リターンの普及に一役買っている感じはしますが、JavaScriptに限らず早期リターンは有効ですよ。ネストの深いifを書かなくて済みます。

    キャンセル

  • 2020/07/14 15:05 編集

    先のコメントでは否定する意見ではありませんと書いたけど、ネストに言及されてるので少し補足

    飽くまでも回答者の同僚さんと同じように早期リターンせずともネストの深くないコード書けるようになればの話です。「早期リターンしないとネストが深くなる人」の解決方法が早期リターンになってしまうならやはり早期リターンはおすすめしません。使っても使わなくても深いネストにならずにコード書ける人なら使っても良いという程度です。
    但しこれは一意見なので、他の人の意見も踏まえて質問者自身で判断してください

    キャンセル

  • 2020/07/14 23:38 編集

    回答、コメントくださった皆様ありがとうございます。
    まず、質問の趣旨だったreturnの意図については、後続の処理を回避するためのガード節であるということが理解できました。
    コメントの議論の内容を全て把握できたわけではありませんが、早期リターンを採用することのメリットデメリットについて理解が深まったように思います。大変勉強になりました。

    キャンセル

+2

この return は処理をそこで打ち切りたいからつけてるだけですね

returnがないと、後続の処理が流れてしまって意図しない結果になるのでしょう。
このコードであれば、 !userということなので、多分ログインしてない状態であれば
404を返して終わり。 という意味かと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/14 23:51

    回答ありがとうございます。参考になりました。

    キャンセル

+1

nodeはいまいちわかりませんがreturnをつけると
コールバック関数においてその後ろに処理が流れない効果が期待できます。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/14 23:51

    回答ありがとうございます。参考になりました。

    キャンセル

+1

回答、みなさんのおっしゃるとおりです。

if (xxx) {
  return res.status(404).send();
}


上記は、下記の意味ですよね。

if (xxx) {
  res.status(404).send()
  return;
}


上の書き方は短くかけるメリットあるのですが returnに戻り値が何もないことが明示的ではないので、戻り値はなんなんだろう?と迷いを生むために、よい書き方ではないと思います。

また、こんな記事もありました。

if文の括弧は省略できるなら省略するのは是か非か | バシャログ。
http://bashalog.c-brains.jp/09/08/05-004630.php

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

質問の意図

私はNode.jsに詳しくありませんが、既存の回答の方向性に疑問を感じるため、あえて回答します。

if文の中でreturnが使われており、if文内の処理を実行させるとres.status(404).send()が実行されますが、これは普通にres.status(404).send()と書くのと何か違いがあるのでしょうか?

意図があってわざわざreturnを加えているとは思うのですが、どのような意図なのか分かりませんでした。

ここでいう「意図」とは、

if (!user) {
  return res.status(404).send()
}

return res.status(404).send()

の違いは何ですか、と解釈しました。

「ガード節を使う意図」は、各コードの挙動を理解していることが前提ですが、その前提に至っていないと感じます。

Node.js Document

検索して、
https://www.google.com/search?q=site%3Anodejs.org+status+send
getメソッドのドキュメントを読んで、
https://nodejs.org/dist/latest-v14.x/docs/api/http.html#http_http_get_options_callback

The callback is invoked with a single argument that is an instance of http.IncomingMessage.

に、うなる

  • 質問コードの第二引数 res はどこに?
  • 質問コードの第一引数 req を利用してststusCodeがとれそうな気が…

Express.js

発想を変えて、"res.status-404" て検索すると、Express.jsのドキュメントがHIT
https://www.google.com/search?q=res.status-404
ようやく、statusメソッドのドキュメントを発見する。

https://expressjs.com/ja/4x/api.html

res.send([body])
Sends the HTTP response.

The body parameter can be a Buffer object, a String, an object, or an Array. For example:

res.status(code)
Sets the HTTP status for the response. It is a chainable alias of Node’s response.statusCode.

質問コードを読む

質問コードは、

if (!user) {
  return res.status(404).send()
}
res.send(user)

Express.jsのドキュメントに従い、

  1. 変数 user がfalsyのとき、「HTTPステークスコード=404」「body=空」を返す
  2. それ以外は、「body=変数 user 値」を返す

という挙動になります。

ガード節(早期リターン)を使うべきか

ガード節(早期リターン)を使うべき論については、私は懐疑的な立場です。
この場合、

return user ? res.send(user) : res.status(404).send();

このように、後期リターンに変更しても、何も問題がありません。


早期リターンが速いという見解もありましたが、「変数 user がtruyhy/falsyのどちらの割合が多いか」の結果を見て、評価順を判断するのが妥当と考えます。

設計や要件にもよると思いますが、ユーザが発見される挙動を正とするなら、この場合は後期リターン型を私は採用します。

Re: __stsh さん

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/15 08:30

    コメントが不足してました、そちらではなく
    >「変数 user がtruyhy/falsyのどちらの割合が多いか」の結果を見て、評価順を判断するのが妥当と考えます。
    ここに対しての質問です

    キャンセル

  • 2020/07/15 13:00

    @hentaiman さん
    そこは私個人のパフォーマンスに対する考え方ですね。
    今回のような単純例だと説明が難しいので、後程、回答に例示コードを加えておきます。

    低評価された方へ
    差し支えなければ、低評価理由を教えて下さい。
    「質問の意図」は主観があるので引っかかりそうですが、質問者さんからは指摘がなく、原因に心当たりがない状況です。

    キャンセル

  • 2020/07/15 13:59

    いえ、大丈夫です。ありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.91%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る