【问题标题】:Why am I getting Promise Pending despite using await in my controller?尽管在我的控制器中使用了等待,为什么我会收到 Promise Pending?
【发布时间】:2020-02-21 18:59:09
【问题描述】:

我有一个存储库,我直接连接到我的模型以插入一些数据,它成功创建了数据,但是当我将控制器连接到这个存储库时,我得到一个空响应,如果我将它记录到存储库本身我得到承诺 。请在下面查看我的代码:-

Repository.js

exports.register = (request) => {
  const data = UserModel.findOne({email: request.email})
    .then(user => {
        if(user)
        {
            return {status: 400, message: 'Email Already exist'}
        } else {
            return bcrypt.genSalt(10,  (err, salt) => {
                const newUser = new UserModel({
                    username: request.username,
                    email: request.email,
                    password: request.password
                });

                return bcrypt.hash(newUser.password, salt, async (err, hash) => {
                    if(err) throw err;
                    newUser.password = hash;
                    return newUser.save()
                        .then(user => {
                            const token = jwt.sign({id: user._id}, process.env.JWT_SECRET, {
                                expiresIn: 86400 // expires in 24 hours
                            });
                            return {status: 200, message: 'Successfully Registered', auth: true, token: token, user: user}
                        })
                        .catch(err => {
                            return {status: 400, message: err}
                        })
                })
            })
        }
})

  console.log(data) // This part is return Promise <pending>
  return data;
};

Controller.js

exports.SeedRegisteration = async (req, res, next) => {
  try {
    let element = await userRepo.register({username: "Testin", email: "Testin@test.com", "password": 
 "joe" });
      return await res.status(200).json({ status: 200, data: element })
 } catch (e) {
    return res.status(400).json({ status: 400, message: e.message });
 }
};

工作正常,但不返回数据

【问题讨论】:

  • 你的exports.register 函数没有返回任何东西——哦,抱歉,它可能有......奇怪的格式
  • 看到这个return bcrypt.hash(newUser.password, salt, async function (err, hash) { 没有返回你希望的结果,你需要保证
  • bcrypt.genSalt(10, (err, salt) =&gt; 也需要承诺
  • 即使我删除了 bcrypt 功能,问题仍然存在
  • 实际上 - bcrypt 确实有“承诺”版本 - 你只需要使用那些

标签: javascript node.js mongodb express mongoose


【解决方案1】:

这是使用 Promise 版本的 bcrypt 的 register 函数(如果您不提供回调,bcrypt 函数会返回一个 Promise

exports.register = (request) => 
    UserModel.findOne({
            email: request.email
    })
    .then(user => {
        if (user) {
            throw 'Email Already exist'
        }
    })
    .then(() => bcrypt.genSalt(10))
    .then(salt => {
        const newUser = new UserModel({
                username: request.username,
                email: request.email,
                password: request.password
            });

        return bcrypt.hash(newUser.password, salt)
        .then((hash) => {
            newUser.password = hash;
            return newUser.save();
        })
    }).then(user => {
        const token = jwt.sign({
            id: user._id
        }, process.env.JWT_SECRET, {
            expiresIn: 86400 // expires in 24 hours
        });
        return {
            status: 200,
            message: 'Successfully Registered',
            auth: true,
            token: token,
            user: user
        }
    }).catch(err => {
        return {
            status: 400,
            message: err
        }
    });

注意:有一个嵌套的 .then - 如果您在 register 中使用 async/await,则此代码可能是完全平坦的 - 但是我不准备对答案进行如此大的重写。现在代码在一个漂亮的几乎平坦的承诺链中,将整个东西转换为 async/await 样式相对简单

【讨论】:

    【解决方案2】:

    返回 promise 的 return 语句太多。请将您的代码更新为以下内容:

        exports.register = (request) => {
        return new Promise((resolve, reject) => {
            try {
                UserModel.findOne({ email: request.email })
                    .then(user => {
                        if (user) {
                            return reject({ status: 400, message: 'Email Already exist' })
                        } else {
                            bcrypt.genSalt(10, (err, salt) => {
                                const newUser = new UserModel({
                                    username: request.username,
                                    email: request.email,
                                    password: request.password
                                });
    
                                bcrypt.hash(newUser.password, salt, async (err, hash) => {
                                    if (err) return reject(err);
                                    newUser.password = hash;
                                    newUser.save()
                                        .then(user => {
                                            const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, {
                                                expiresIn: 86400 // expires in 24 hours
                                            });
                                            return resolve({ status: 200, message: 'Successfully Registered', auth: true, token: token, user: user })
                                        })
                                        .catch(err => {
                                            return reject({ status: 400, message: err })
                                        })
                                })
                            })
                        }
                    }).catch(err => {
                        return reject(err)
                    })
            } catch (error) {
                return reject(error)
            }
        });
    };
    

    【讨论】:

    • 我觉得这里的promise是没有必要的,Jaromanda X 好像不用碰控制器就直截了当
    • 好吧,您实际上并没有触摸控制器。我刚刚更新了Repository 文件。在您的controller 中,您已经拥有try/catch 任何方式
    • 这段代码演示了 Promise 构造函数反模式的完美使用...UserModel.findOne 返回一个 Promise,所以为什么要把它包装在 new Promise 中。此外,如果您不提供回调参数,bcrypt 方法确实会返回 Promises,所以为什么不充分利用 Promise 链来制作整洁的代码,而无需您进入那里的厄运回调金字塔
    • 嗯。我理解这里的promise anti-pattern 论点。谢谢指出
    猜你喜欢
    • 2023-01-12
    • 1970-01-01
    • 1970-01-01
    • 2018-07-20
    • 1970-01-01
    • 2020-03-04
    • 2018-02-14
    • 2021-04-26
    • 1970-01-01
    相关资源
    最近更新 更多