【问题标题】:Node middleware wait for function to complete before continuing节点中间件在继续之前等待功能完成
【发布时间】:2020-01-10 21:14:09
【问题描述】:

我在 Node 中导出此函数,但我需要在其余代码继续之前完成 Booking.find 函数。

原文:

    module.exports = function() {
    return function secured(req, res, next) {
        if (req.user) {
        const mongoose = require('mongoose');
        const Booking = mongoose.model('Booking');
        Booking.find((err, docs) => {  // I need this to run first
            bookingsCount = docs.length;
        });
        const userProfile = req.user;
        res.locals = {
            count: bookingsCount,  // so that when the page loads this var is available
            userProfile: JSON.stringify(userProfile, null, 2),
            name: userProfile.displayName,
            loggedInEmail: userProfile.emails[0].value,
            isAuthenticated: req.isAuthenticated(),
        };

        return next();
        }
        req.session.returnTo = req.originalUrl;
        res.redirect('/login');
    };
    };

我尝试使用回调创建单独的函数,但我认为这不正确,因为那将是一种异步方法,但我相信我需要使这部分同步。

然后我在How to wait for the return of a Mongoose search async await 下尝试了这个,它似乎每次都正确返回。

更新:

    module.exports = function () {
        return async function secured(req, res, next) { // added async
            if (req.user) {
                const mongoose = require('mongoose');
                const Booking = mongoose.model('Booking');
                await Booking.find((err, docs) => { // added await
                    bookingsCount = docs.length;
                });
                const userProfile = req.user;
                res.locals = {
                    count: bookingsCount,
                    userProfile: JSON.stringify(userProfile, null, 2),
                    name: userProfile.displayName,
                    loggedInEmail: userProfile.emails[0].value,
                    isAuthenticated: req.isAuthenticated(),

                };
                return next();
            }
            req.session.returnTo = req.originalUrl;
            res.redirect('/login');
        };
    };

在这种情况下,对于每个页面请求,在中间件中正确使用 await 是否正确,我可以安全地假设在解决 Booking.find 承诺之前页面不会加载吗?

按照建议尝试 1:

    module.exports = function () {
        return async function secured(req, res, next) {
            if (req.user) {
                let docs;

                try {
                    docs = await Booking.find((err, docs) => {
                        const bookingsCount = docs.length;
                        const userProfile = req.user;

                        res.locals = {
                            count: bookingsCount,
                            userProfile: JSON.stringify(userProfile, null, 2),
                            name: userProfile.displayName,
                            loggedInEmail: userProfile.emails[0].value,
                            isAuthenticated: req.isAuthenticated(),
                        };
                    });

                    return next();
                } catch (err) {
                    console.log(err);
                    return next(err);
                }
            }
            req.session.returnTo = req.originalUrl;
            res.redirect('/login');
        };
    };

按要求预订模型:

    const mongoose = require('mongoose');

    const bookingSchema = new mongoose.Schema({
      firstName: {
        type: String,
        required: 'This field is required',
      },
      lastName: {
        type: String,
        required: 'This field is required',
      },
      tourType: {
        type: String,
        required: 'This field is required',
      },
      dateBooked: {
        type: String,
        required: 'This field is required',
      },
      tourDate: {
        type: String,
        required: 'This field is required',
      },
      pax: {
        type: String,
        required: 'This field is required',
      },
      phone: {
        type: String,
        required: 'This field is required',
      },
      customerEmail: {
        type: String,
        required: 'This field is required',
      },
      pickupAddress: {
        type: String,
        required: 'This field is required',
      },
      operatorName: {
        type: String,
        required: 'This field is required',
      },
      paidStatus: {
        type: String,
        required: 'This field is required',
      },
      notes: {
        type: String,
      },
      guidesName: {
        type: String,
      },
      guidesEmail: {
        type: String,
      },
      bookingCreatedSent: {
        type: Boolean,
      },
      calendarEventCreated: {
        type: Boolean,
      },
      clientReminderSent: {
        type: Boolean,
      },
      remindOperators: {
        type: Boolean,
      },
      remindGoCapeGuides: {
        type: Boolean,
      },
      feedbackSent: {
        type: Boolean,
      },
    });

    // Custom validation for email
    bookingSchema.path('customerEmail').validate((val) => {
      emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
      return emailRegex.test(val);
    }, 'Invalid e-mail.');

    mongoose.model('Booking', bookingSchema);

DB.js - 模型是依赖的

const mongoose = require('mongoose');
require('dotenv').config();
env = process.env.NODE_ENV;
envString = env;

// mongoDB connection string
const url = process.env['MONGO_DB_URL' + envString];
console.log(url);
mongoose.connect(url, {useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false})
    .then(() => {
      console.log('connected!', process.env.PORT || '8000');
    })
    .catch((err) => console.log(err));

//db.close();

require('./booking.model');

可用的尝试:

    module.exports = function() {
    return async function secured(req, res, next) {
        if (req.user) {
        const Booking = require('../model/booking.model');
        let docs;

        try {
            docs = await Booking.find((err, docs) => {
            const bookingsCount = docs.length;
            const userProfile = req.user;

            res.locals = {
                count: bookingsCount,
                userProfile: JSON.stringify(userProfile, null, 2),
                name: userProfile.displayName,
                loggedInEmail: userProfile.emails[0].value,
                isAuthenticated: req.isAuthenticated(),
            };
            });

            return next();
        } catch (err) {
            console.log(err);
            return next(err);
        }
        }
        req.session.returnTo = req.originalUrl;
        res.redirect('/login');
    };
    };       

【问题讨论】:

    标签: node.js mongoose async-await


    【解决方案1】:

    在您更新的代码中,您都在尝试使用等待和回调。

    还要在 await 中捕获错误,我们需要使用 try catch 块。

    所以你可以像这样重写你的函数:

    const mongoose = require("mongoose");
    const Booking = mongoose.model("Booking");
    
    module.exports = function() {
      return async function secured(req, res, next) {
        if (req.user) {
          let docs;
    
          try {
            docs = await Booking.find();
    
            const bookingsCount = docs.length;
            const userProfile = req.user;
    
            res.locals = {
              count: bookingsCount,
              userProfile: JSON.stringify(userProfile, null, 2),
              name: userProfile.displayName,
              loggedInEmail: userProfile.emails[0].value,
              isAuthenticated: req.isAuthenticated()
            };
            return next();
          } catch (err) {
            console.log(err);
            return next(err);
          }
        }
        req.session.returnTo = req.originalUrl;
        res.redirect("/login");
      };
    };
    

    而要解决原代码中的问题,你需要像这样将里面的res.locals相关代码移到Find回调中,这样只有在Find工作后才有效。

    module.exports = function() {
      return function secured(req, res, next) {
        if (req.user) {
          const mongoose = require("mongoose");
          const Booking = mongoose.model("Booking");
          Booking.find((err, docs) => {
            bookingsCount = docs.length;
            const userProfile = req.user;
            res.locals = {
              count: bookingsCount,
              userProfile: JSON.stringify(userProfile, null, 2),
              name: userProfile.displayName,
              loggedInEmail: userProfile.emails[0].value,
              isAuthenticated: req.isAuthenticated()
            };
    
            return next();
          });
    
          next();
        }
        req.session.returnTo = req.originalUrl;
        res.redirect("/login");
      };
    };
    

    更新:

    您需要在这样的架构代码之后在预订中导出您的模型:

    module.exports = mongoose.model('Booking', bookingSchema);
    

    并在你的函数中像这样导入它:

    const Booking = require("../models/booking"); //TODO: update your path
    

    代替这一行:

    const Booking = mongoose.model("Booking");
    

    【讨论】:

    • 谢谢你,太好了,我看到你的 try 逻辑可以捕获但是实现你的 sn-ps 会产生 Booking is not defined - 我在我的问题中添加了我的实现尝试。
    • @ZADorkMan 最好在您定义预订架构时导出预订模型,您能否将架构代码添加到问题中,以便我可以展示该怎么做。
    • @ZADorkMan 我在回答的最后做了一个更新,你能做出这些改变并尝试吗?
    • 啊哈,当然,我忘了添加模型调用。但是我在if (req.user) { 下方添加了const mongoose = require('mongoose'); const Booking = mongoose.model('Booking');,它似乎可以工作,但如果我可能会问,你为什么建议改为更新模型导出?
    • @ZADorkMan 您需要在使用 mongoose.model 时指定架构。请尝试我的代码。
    猜你喜欢
    • 2018-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-26
    • 1970-01-01
    相关资源
    最近更新 更多