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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

Express

ExpressはNode.jsのWebアプリケーションフレームワークです。 マルチページを構築するための機能セットおよびハイブリッドのWebアプリケーションを提供します。

Q&A

解決済

3回答

9821閲覧

node.js(passport)のfunction()やdone()の意味、動きを教えてください

退会済みユーザー

退会済みユーザー

総合スコア0

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

Express

ExpressはNode.jsのWebアプリケーションフレームワークです。 マルチページを構築するための機能セットおよびハイブリッドのWebアプリケーションを提供します。

0グッド

1クリップ

投稿2016/10/05 21:44

編集2016/10/05 21:48

###前提・実現したいこと
node.js + express + passportでGoogleアカウントでログインする機能を作っています。
passportのGuideを見ても意味がわからない状態です。

###発生している問題・エラーメッセージ

function()とdone()がどうのようなことを行っているのかわかりません。
例として、以下のようにpassportのコードがあった場合、
fucntion()とdone()が何をしているのか教えてください

node.js

1passport.serializeUser(function(user, done) { 2 done(null, user.id); 3}); 4 5passport.deserializeUser(function(id, done) { 6 User.findById(id, function(err, user) { 7 done(err, user); 8 }); 9});

###試したこと
ぐぐったところ、function()はコールバック関数という名前らしいですが、
function()の引数の説明や、function(res,req)やfunction(user,done)が実際にどのような意味を持っているのかまったくわかりませんでした。
done()についても同様です。

上記コードをもとに説明をお願いします。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

コールバック関数等に関しては,下記記事に詳細な解説があるので読んでみてください.

JavaScript中級者への道【5. コールバック関数】 - Qiita
(発展) JavaScriptは如何にしてAsync/Awaitを獲得したのか Qiita版 - Qiita
(補足)日本語のコードで理解するPromise - Qiita

ここでのfunction () { ... } は「準備ができたタイミングで関数を呼ぶ」の対象となるそれです.


Passportのdoneに関しては以下に日本語で説明があります.

Passport | 設定

要するに,doneはEventEmitter的に,「成功したよ」「失敗したよ」とPassport内部に対して通知するイベントを発行しているようなものでしょうか.

このようにストラテジーに処理を委譲することで、検証用コールバックは、Passportとデータベースを疎に保ちます。 これによりアプリケーションは、認証レイヤーでの様々な前提条件にとらわれず、ユーザー情報をどのように格納するか自由に選択できます。

  • serializeUser 「ユーザオブジェクトを与えてやるから,保存に成功したらdoneの第2引数ででユーザIDを渡してくれ.エラーがあったときは第1引数にそれを渡してくれ.続く処理は俺(Passport)がやるからとりあえずその仕事だけよろしく.」
  • deserializeUser 「ユーザIDを渡してやるから,復元に成功したらdoneの第2引数でユーザオブジェクトを渡してくれ.エラーがあったときは第1引数にそれを渡してくれ.続く処理は俺(Passport)がやるからとりあえずその仕事だけよろしく.」

こういうことですね.実際にどのように保存や復元を行うかはプログラマが自由に選択できるということです.関数の返り値を使わずにわざわざdoneを実行させるのは,JavaScriptはおもに,非同期処理の実現にはコールバック関数モデルを採用しているからです.

JavaScript

1User.findById(id, function(err, user) { 2 /* 成功または失敗時の処理 */ 3});

User.findByIdがこのような使い方である以上,完了時にdoneを呼ばせるしかないですよね.
(もしPromiseを返すような設計になっていれば必ずしもそうではないのですが…)

投稿2016/10/05 23:04

編集2016/10/06 03:10
mpyw

総合スコア5223

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mpyw

2016/10/05 23:06

また,Expressはコールバック関数ベースの設計となっていて扱いにくいので,それをPromiseベースにして使いやすくしてくれた koa というフレームワークも存在します.個人的にはこちらのほうが断然おすすめです.
mpyw

2016/10/06 03:12

JavaScriptの非同期処理を完全に理解するには, コールバック関数 → Promise → Generator → async/await という4段階の歴史的な発展を理解する必要がありますが,少しずつ学んでいってください.最初の鬼門はPromiseかもしれません.
guest

0

良い質問だと思います。まず、Javascript の非同期プログラミングの構造を覚えて頂く必要があります。少し長くなります。

言語を問わず、プログラムがネットワークで通信する、ファイルを読む、データベースを読むなど外の世界へアクセスするときは、処理に時間がかかる場合があり、実行を開始すると終了するまで待つ必要があります。javascript 以外の言語では、外部へアクセスするライブラリを呼び出すと、結果が返されます。これは外部へのアクセスを開始してから終了するまで一時的にプログラムを停止して待ち、結果を受け取って返すことで実現されています。

javascript はシングルスレッドで動く仕様となっており、プログラムの実行を止めて待つと、すべての処理が止まってしまい性能が出ません。そこで、アクセスを開始する命令を出した後、終わったときに関数を呼び出してもらうという方法で続きの処理を実行します。たとえば、ファイルから読み出すときは、

javascript

1var fs = require('fs'); 2function test() { 3 fs.readFile('./test.txt', 'utf8', function (err, text) { 4 console.log('end.'); 5 console.log(text); 6 }); 7 console.log('start.'); 8} 9test();

のように書きますが、test関数から fs.readFile 関数を呼び出して、その呼出が終わった時点では、コールバックは呼び出されていません。いつ呼び出されるかというと、コンソールに'start.'を印刷して test() の実行が終わった後です。他にも外部へのアクセスをした結果を待っているものがあれば、早いもの順でコールバックが呼び出されます。このコールバック関数は Javascript の処理系から呼び出されるので、プログラマの書いたコードから呼び出されるものではありません。

さて、上記の例でファイルを読み出した後の処理はすべてコールバック関数の中で実行しなければならないことに注意してください。すると、test()関数の中でプログラムの続きの処理を全部記述しなければならなくなり、サブルーチン化、モジュール化がまったくできなくなってしまいます。そこで、サブルーチンにコールバックを渡して、続きの処理を呼び出し側で記述できるようにします。例えば、

javascript

1var fs = require('fs'); 2function test(done) { 3 fs.readFile('./test.txt', 'utf8', function (err, text) { 4 console.log('end.'); 5 done(text) 6 }); 7 console.log('start.'); 8} 9 10test(function (text) { 11 console.log(text); 12});

のように修正することで、 test() 関数はファイルを読み出し、その続きの処理(ここでは、コンソールにファイルの内容を印刷する)は呼び出し側に記述できるようになりました。

Javascript では、他のモジュールの関数を呼び出すと、いつ非同期が呼び出されるのかわからないので、常にこの作法に従う必要があります。

passport もこの作法に従っているわけです。function(user, done) {done(null, user.id);}); は他の言語なら function(user) {return user.id;}); となるところですが、上記のマナーにしたがって、返却値ではなく、コールバック関数の引数で値を返しているわけです。

例にあげてもらったコードですと、コールバックの中に非同期処理が含まれておらず、コールバック関数が呼ばれるとすぐに done を呼ぶことになるので、なぜ返却値で返さないのかわからないと思います。シリアライズやデシリアライズの処理中に外部へのアクセス(例えばデータベースへのアクセス)が途中で必要になる場合にどう記述するか考えていただければ、なぜ、このような構造になっていることがわかるかと思います。

投稿2016/10/05 23:45

mit0223

総合スコア3401

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

JavaScriptの関数は数値や文字列と同じような扱いが出来る言語です。
C言語などでは考えも付かないこんな使い方ができます。

JavaScript

1// 変数に代入する 2var add_2 = function (it) { return it + 2; }; 3console.log(add_2(3)); # 5 4 5// 関数を戻り値として返す 6var add = function (a) { 7 return function (b) { return a + b; }; 8}; 9console.log(add(3)(4)); # 7 10 11// 関数を引数に設定 12var hoge = function (cb) { 13 return cb(4, 5); 14} 15console.log(hoge(function(a, b){ return a + b; })); # 9

以上、関数がまるで数値や文字列のように扱えることがわかりました。
関数がこの特性を持つ事を第一級関数と呼びます。

Node.jsでは非同期処理を実現するために
関数を引数に設定できるという特性をフル活用します。

Webサーバーやデータベースサーバーにリクエストを投げた後なんて、レスポンスが帰ってくるまでCPUはすること無いから暇なんです。
Node.jsでは「終わったら引数として渡しておいた関数実行しといてね、あとよろしく。」…という使い方をします。

後の説明はmpywさん、mit0223さんが詳しくされていますので割愛します。

投稿2016/10/06 00:25

miyabi-sun

総合スコア21158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問