Node.js Mongoose Promise 迷路了
Posted
技术标签:
【中文标题】Node.js Mongoose Promise 迷路了【英文标题】:Node.js Mongoose Promise getting lost 【发布时间】:2018-03-07 10:11:20 【问题描述】:我有一个带有 mongoDB 的 Node.js API。有一个路由可以创建一个用户并且需要对密码进行哈希处理,为此我使用了 bcryptjs 包。
路线如下所示:
router.route('/user')
.post(function(req, res)
if(req.body.password === req.body.passwordConfirm)
userManager.addUser(req.body)
.then(function(response) // waiting for the result of the mongoDB save
res.send(data:response);
);
else
res.send(err:'passwords do not match');
)
和 userManager.addUSer:
this.addUser = function(userobject)
bcrypt.genSalt(10, function(err, salt) // generate a salt
if(err !== null)
console.log(err);
else
bcrypt.hash(userobject.password_hash, salt, function(err, hash) // hash pw
if(err !== null)
console.log(err);
else
userobject.password_hash = hash; // store hash in user obj
var user = new User(userobject);
return user.save().catch(function(err) // save user in mongoDB
console.log(err);
);
);
);
;
我收到一条错误消息:“无法读取未定义的属性 'then'”,这告诉我我没有收到来自 addUser 的承诺。我看了看,遗憾的是 bcryptjs 不使用承诺,但是,猫鼬会。 (添加这个:
var mongoose = require('mongoose').Promise = Promise;
没有帮助)
我尝试用reject 和resolve 将函数包装在一个promise 中,但这给出了这个错误:“TypeError: Promise resolver undefined is not a function”。
如何获得 mongoose 的 save() 函数返回到 post 路由中的 .then() 的承诺?我尝试在两个 bcrypt 函数前面添加 return ,但这也没有用..
欢迎提出任何建议!
【问题讨论】:
你没有从你的this.addUser
返回一个Promise。
要清楚,你不会从this.addUser
返回任何东西
@Jaromanda X 是的,我现在明白了,我是 Promise 的新手,我想我迷失了不支持 Promise 的 API..
【参考方案1】:
您的addUser
函数永远不会将承诺返回给它的调用者。您正在通过bcrypt.hash
回调函数执行return
,但这与addUser
的返回值无关。
看起来addUser
必须使用一些未启用 Promise 的 API,因此您只能使用 new Promise
,类似这样的事情(请参阅 ***
cmets):
this.addUser = function(userobject)
return new Promise(function(resolve, reject) // ***
bcrypt.genSalt(10, function(err, salt) // generate a salt
if(err !== null)
reject(err); // ***
else
bcrypt.hash(userobject.password_hash, salt, function(err, hash) // hash pw
if(err !== null)
reject(err); // ***
else
userobject.password_hash = hash; // store hash in user obj
var user = new User(userobject);
resolve(user.save()); // *** save user in mongoDB
);
);
);
;
还请注意,我没有 addUser
只是吞咽错误;相反,它们被传播给调用者。调用者应该处理它们(即使“处理”只是记录)。
【讨论】:
【参考方案2】:您不会从 this.addUser
返回 Promise,您必须将基于 bcrypt
的回调转换为 Promise。您可以使用例如转换整个 bcrypt
API 以支持基于 Promise 的函数。蓝鸟库的promisifyAll
,或者像这样使用new Promise
手动完成:
this.addUser = function(userobject)
return new Promise((resolve, reject) =>
bcrypt.genSalt(10, (err, salt) =>
if (err)
reject(err);
else
bcrypt.hash(userobject.password_hash, salt, function(err, hash)
if (err)
reject(err)
else
resolve(hash)
)
);
)
.then(hash =>
userobject.password_hash = hash; // store hash in user obj
var user = new User(userobject);
return user.save() // save user in mongoDB
)
.catch(function(err)
console.log(err);
);
或者那样:
this.addUser = function(userobject)
return new Promise((resolve, reject) =>
bcrypt.genSalt(10, (err, salt) =>
if (err)
reject(err);
else
resolve(salt);
);
)
.then(salt =>
return new Promise((resolve, reject) =>
bcrypt.hash(userobject.password_hash, salt, function(err, hash)
if (err)
reject(err)
else
resolve(hash)
)
)
)
.then(hash =>
userobject.password_hash = hash; // store hash in user obj
var user = new User(userobject);
return user.save() // save user in mongoDB
)
.catch(function(err)
console.log(err);
);
【讨论】:
【参考方案3】:在对 bcryptjs 的更改日志进行更多挖掘后,我发现他们添加了 Promise,但没有更新文档。如果省略回调,则 genSalt en hash 方法将返回一个 Promise。这将转化为:
this.addUser = function(userobject)
return bcrypt.genSalt(10).then((salt) =>
return bcrypt.hash(userobject.password, salt).then((hash) =>
userobject.password_hash = hash;
var user = new User(userobject);
return user.save();
);
);
;
【讨论】:
以上是关于Node.js Mongoose Promise 迷路了的主要内容,如果未能解决你的问题,请参考以下文章
Node js,使用带有Q promise的mongoose不会调用reject函数
[js高手之路]Node.js+jade+express+mongodb+mongoose+promise实现todolist
在 Node.js + Express 中使用 Promise 处理错误
使用 Node.Js 和 Promises,你如何返回一个已经实现的 Promise? [复制]