2016-10-15 3 views
1

私はBluebirdに新規で、新しいユーザーを作成しようとしていますが、reject関数が期待通りに機能しません。Bluebirdが新しいユーザーを作成する

エラーThere nickname is already in useを起動しても、userが作成されるという問題があります。

ここではコードを貼り付けます。

user.jsの

var User = require('../models/user'); 
var Promise = require('bluebird'); 

module.exports = { 
    validateFields: function (nickname) { 
    return new Promise(function (response, reject) { 
     if (!nickname) { 
     reject('You must provide the nickname'); 
     } else if (nickname.length < 4 || nickname.length > 20) { 
     reject('The nickname must be longer than 4 and shorter than 20 characters'); 
     } else { 
     nickname = nickname.trim(); 
     User.findOne({ "nickname": nickname }).exec() 
      .then(function (user) { 
      if (user) { 
       reject('There nickname is already in use'); 
      } else { 
       response(); 
      } 
      }, function (err) { 
      reject('There is an error trying to verify the nickname'); 
      }); 
     } 
    }); 
    }, 
    registerUser: function (user_id, nickname) { 
    return new User({ user_id: user_id, nickname: nickname }).save(); 
    } 
}; 

register.js

var validator = require('validator'); 
var Promise = require('bluebird'); 
var Account = require('../../models/account'); 

module.exports = { 
    validateFields: function (email, password) { 
    return new Promise(function (response, reject) { 
     if (!email) { 
     reject('You must provide the email'); 
     } else if (!password) { 
     reject('You must provide the password'); 
     } else if (email.length < 6) { 
     reject('The email is too short'); 
     } else if (email.length > 40) { 
     reject('The email is too long'); 
     } else if (!validator.isEmail(email)) { 
     reject('The email is not valid'); 
     } else { 
     Account.findOne({ email: email }).exec() 
      .then(function (account) { 
      if (account) { 
       reject('There is already an email'); 
      } else { 
       console.log(account); 
       response(); 
      } 
      }, function (err) { 
      reject('There is an error trying to verify the email'); 
      }); 
     } 
    }); 
    }, 
    registerAccount: function (email, password) { 
    return new Account({ email: email, password: password }).save(); 
    } 
}; 

routes.js

var Promise = require('bluebird'); 

var user  = require('./routes/user'); 
var account = require('./routes/auth/register'); 

router.post('/register', function (req, res, next) { 
    account.validateFields(req.body.email, req.body.password) 
    .then(function() { 
     return user.validateFields(req.body.nickname); 
    }, function (err) { 
     return res.status(400).json({ msg: err }); 
    }) 
    .then(function() { 
     req.body.email = req.body.email.trim(); 
     req.body.password = req.body.password.trim(); 
     console.log('bien'); 
     return account.registerAccount(req.body.email, req.body.password); 
    }, function (err) { 
     console.log('mal'); 
     return res.status(400).json({ msg: 'There was an error trying to save the email' }); 
    }) 
    .then(function (data) { 
     return user.registerUser(data, req.body.nickname); 
    }, function (err) { 
     return res.status(400).json({ msg: 'There was an error trying to save the user' }); 
    }) 
    .then(function() { 
     return res.status(200); 
    }, function (err) { 
     console.log(err); 
     return res.status(400).json({ msg: err }); 
    }) 
    .catch(function (err) { 
     console.log('catch'); 
     return res.status(400).json({ msg: err }); 
    }); 
}); 

アドバイスに感謝します。

UPDATEちょうど約束で開始し、ベストプラクティスを探している皆を明確にするために、私はthisリンクが便利ですね。

+1

['Promise'コンストラクタのアンチパターン](http://stackoverflow.com/q/23803743/1048572)は避けるべきです。 [ES6 Promisesで事前条件を慣習的に扱う]を見てください(http://stackoverflow.com/q/35856041/1048572) – Bergi

+0

は、検証を受け入れる '新しい約束事 'の作成に関連するあなたのヒントです。 'mongoose'約束? 'Promise.reject(新しいエラー(何かエラーが発生した場合))')と 'mongoose'約束を返すような検証を分けるべきでしょうか? – DevStarlight

+1

はい、正確です。あなたがマングースの約束を返すのではなく、ブルーバードの約束を返すことを望むなら、 'return Promise.resolve(... .findOne(...).exec())、then(...)' – Bergi

答えて

2

TLDR;エラー後にpromise chainの後続の関数を呼び出さないようにするには、.catch()または.then(success、エラー)のエラーをキャッチしないでください。エラーの後で望ましくない呼び出しを行うことなく、非同期呼び出しチェーン全体の結果を得るためにチェーンの終わりにのみキャッチします。

さて、ちょうど拒否約束返す関数を想像してみましょう:次に

function fakeForbiddenAsyncOperation(){ 
    return new Promise(function(resolve , reject){ 
     return reject('This operation is forbidden'); 
    }); 
} 

を、のような約束チェーン:

fakeForbiddenAsyncOperation().then(
function(){ 
    console.log('first parameter, success'); 
}, 
function(err){ 
    console.log('second parameter, failure: ' + err); 
}) 
.then(function(){ 
    console.log('This log is called, because the previous error was catched in the second then() lambda'); 
}) 
.catch(console.log); 

は、このログが呼び出される」ことにconsole.logをできるようになります。エラーが処理されているため、実行する。出力は次のようになります。

second parameter, failure: This operation is forbidden

This log is called, because the previous error was catched in the second then() lambda

あなたのコードで何をしたいのか

、検証の前のエラーがある場合に作成されることにユーザーを防止し、より多くのようなものです:

出力
fakeForbiddenAsyncOperation().then(
function(){ 
    console.log('first parameter, success'); 
}) 
.then(function(){ 
    console.log('This log is called'); 
} , function(err){ 
    console.log('There was an err: ' + err); 
    console.log('this is called at the end, and the previous "this log is called" log wasn\'t fired because there was an unhandled rejection'); 
}); 

次のとおりです。

There was an err: Error: This operation is forbidden

this is called at the end, and the previous "this log is called" log wasnt fired because there was an unhandled rejection

だから、「最初のパラメータ、成功」ログは決して火(そう、User.create()関数、または以前のエラーがある場合に実行したくない他の操作、さもない)。

forbiddenAsyncOperation().then(
function(){ 
    console.log('first parameter, success'); 
}) 
.then(function(){ 
    console.log('This log is called'); 
}) 
.catch(function(){ 
    console.log('this is called at the end, and the previous "this log is called" log wasn\'t fired because there was an unhandled rejection'); 
}); 

は以前のように動作します:

Bluebird documentationではなく.then(成功、失敗)の)(.catch使用することをお勧めします。

あなたは多分処理したいまた、2つのマイナーな問題があります例。また

is better to reject errors instead of strings

reject(new Error('The nickname must be longer than 4 and shorter than 20 characters')); 

ではなく、コンソール内だけでメッセージのエラースタックトレースを出力します。

+0

私は、コールバックとして考えることによって、約束を間違った方法で使用していました。今私はそれを得た。ありがとう! – DevStarlight

関連する問題