gpt4 book ai didi

javascript - 在接受服务器请求之前等待种子数据

转载 作者:行者123 更新时间:2023-12-03 03:34:31 26 4
gpt4 key购买 nike

正如标题所暗示的,这里的问题是在加载基本根目录后运行的 server.js 中的一个函数。下面你可以看到函数调用和根。

seedDB();
app.get("/",function(req,res)
{
examBoard.find({}, function (err, examBoard)
{
console.log("examBoard.length: " + examBoard.length);
res.render("landing", { examBoard: examBoard });
});
});

该函数执行数据库的基本播种,因此必须在基本根之前运行。它输出您在下图中可以看到的内容(大部分输出被切断)。

enter image description here

红框中的输出是 console.log 的结果。在基根中。这里是 app.listen它位于代码的最底部,上面的所有内容。
app.listen(process.env.PORT, process.env.IP,function()
{
console.log("Server started");
});

这是 seedDB 的代码完整的代码包括这个hastebin链接( https://hastebin.com/acecofoqap.lua)中的数组(认为包含它们会有点过分,因为它们相当大):
function seedDB() {
user.remove({}, function (err) {
if (err) {
console.log("Could not remove user\n" + err);
}
else {
console.log("Removed old user");
examBoard.remove({}, function (err) {
if (err) {
console.log("Could not remove examboards\n" + err);
}
else {
console.log("Removed old examboards");
question.remove({}, function (err) {
if (err) {
console.log("Could not remove questions\n" + err);
}
else {
console.log("Removed old questions");
user.register(new user
({
username: "admin",
email: "jonathanwoollettlight@gmail.com",
role: "admin"
}),
"lu134r7n75q5psbzwgch", function (err, user) {
if (err) {
console.log("Failed to add admin\n" + err);
}
else {
console.log("Admin added");
examboardData.forEach(function (examSeed) {
examBoard.create(examSeed, function (err, exam) {
console.log("Creating new examboard");
if (err) {
console.log("Could not create new examboard\n" + err);
}
else {
console.log("Created examboard");
}
});
});
var topicIncrementor = 0;
questionData.forEach(function (questionSeed) {
question.create(questionSeed, function (err, question) {
if (err) {
console.log("Could not create new question\n" + err);
}
else {
console.log("Created question");
examBoard.find({}, function (err, exams) {
for (var i = 0; i < exams.length; i++) {
for (var t = 0; t < exams[i].modules.length; t++) {
for (var q = math.floor(topicIncrementor / 12); q < exams[i].modules[t].topics.length; q++) {
exams[i].modules[t].topics[q].questions.push(question);
topicIncrementor++;
}
topicIncrementor = 0;
}
exams[i].save();
}
});
}
});
});
}
});
}
});
}
});
}
});
}
module.exports = seedDB;

为了让我的程序在这里工作, seedDB函数必须在基本根之前运行,如果您可以提供解决方案或仅将我指向正确的方向,将不胜感激。

最佳答案

底线是您的 seedDB()需要异步回调或 Promise 解析本身,然后仅在该操作完成时启动服务器的“http”部分。原因是服务器在确认加载数据之前甚至不接受请求。

实现种子功能

在现代版本的 nodejs 中,最简单的实现方法是使用 async/await句法

async function seedDB() {

// Remove existing data
await Promise.all(
[user,examBoard,question].map( m => m.remove({}) )
);

// Create the user, wrap callback method with Promise
await new Promise((resolve,reject) => {
user.register( new user({
username: "admin",
email: "jonathanwoollettlight@gmail.com",
role: "admin"
}),"lu134r7n75q5psbzwgch", (err, user) => {
if (err) reject(err);
resolve(user);
});
});

// Create examBoard. .create() does actually accept an array.
// Keep the results as well
var exams = await examboard.create(examboadData);

// Create questions. Same thing
var questions = question.create(questionData);

// Add questions to each exam topic

for ( let question of questions ) {
for ( var i = 0; i < exams.length; i++ ) {
for ( var t = 0; t < exams[i].modules.length; t++ ) {
for ( var q = 0; q < exams[i].modules[t].topics.length; q++ ) {
exams[i].modules[t].topics[q].questions.push(question);
}
}
await exams[i].save();
}
}

}

稍微回一下,看看用普通的 Promise 会是什么样子执行:
function seedDB() {

// Remove existing data
return Promise.all(
[user,examBoard,question].map( m => m.remove({}) )
)
.then( () =>
// Create the user, wrap callback method with Promise
new Promise((resolve,reject) => {
user.register( new user({
username: "admin",
email: "jonathanwoollettlight@gmail.com",
role: "admin"
}),"lu134r7n75q5psbzwgch", (err, user) => {
if (err) reject(err);
resolve(user);
});
})
)
.then( () =>
Promise.all(
// Create examBoard. .create() does actually accept an array.
// Keep the results as well
examboard.create(examboadData),

// Create questions. Same thing
question.create(questionData)
)
)
.then( ([exams, questions]) => {
// Add questions to each exam topic
var items = [];

for ( let question of questions ) {
for ( var i = 0; i < exams.length; i++ ) {
for ( var t = 0; t < exams[i].modules.length; t++ ) {
for ( var q = 0; q < exams[i].modules[t].topics.length; q++ ) {
exams[i].modules[t].topics[q].questions.push(question);
}
}
items.push(exams[i].save().exec());
}
}

return Promise.all(items).then( () => Promise.resolve() );
});

}

所以它基本上是一样的,除了我们“明显地链接” promise 而不是使用 await可以在现代环境中使用的糖。

这里要理解的关键点是“mongoose API 中的所有内容都返回一个 Promise”,因此有更简洁的方法来实现等待完成和调用链。

这适用于 .remove() 的简单链接。调用:
  await Promise.all(
[user,examBoard,question].map( m => m.remove({}) )
);

这是我通过“循环所有注册模型”“播种”初始数据时通常写的内容:
  await Promise.all(
Object.keys(conn.models).map( m => conn.models[m].remove({}) )
)

或者,如果有些方法实际上没有 promise ,那么你总是可以将它们“包装”在 Promise 中,就像 user.register 一样。假设它是“仅回调”。实际实现可能会有所不同,但这是通过演示包装回调的常用方法。

归根结底,一切都在正常等待,整个功能只有在一切都完成后才能解决。这使您可以继续进行重要的部分。

实现等待服务器启动

使种子函数成为“异步”返回的全部原因是我们知道它何时完成,然后只会调用 .listen()确认后的方法,因此服务器在数据准备好之前不会接受请求。

同样,根据可用的 Node 版本,您可以使用 async/await语法或链接要解决的 promise 。

所以使用 async/await ,您的主服务器启动应如下所示:
const mongoose = require('mongoose'),
app = require('express')();
// and other module includes, including the seedDB source

const uri = 'mongodb://localhost/test',
options = { useMongoClient: true };

mongoose.Promise = global.Promise;
mongoose.set('debug',true); // useful before deployment to see requests

// Possibly other express handler set up

// Root handler
app.get('/', function(req,res) {
examBoard.find({}, function (err, examBoard) {
console.log("examBoard.length: " + examBoard.length);
res.render("landing", { examBoard: examBoard });
});
});

// Main startup
(async function() {
try {

const conn = await mongoose.connect(uri,options);

// Seed and await
await seedDB();

// Then we listen
await app.listen(5858);

console.log('server listening');
} catch(e) {
console.error(e);
mongoose.disconnect(); // Probably not realistically
}
})();
async/await这里的 suguar 允许您简单地按顺序列出每个操作,也可以在 try/catch 中列出。 block ,它将捕获任何错误而没有所有其他回调困惑。

或者,“链接”方法是:
const mongoose = require('mongoose'),
app = require('express')();
// and other module includes, including the seedDB source

const uri = 'mongodb://localhost/test',
options = { useMongoClient: true };

mongoose.Promise = global.Promise;
mongoose.set('debug',true); // useful before deployment to see requests

// Possibly other express handler set up

// Root handler
app.get('/', function(req,res) {
examBoard.find({}, function (err, examBoard) {
console.log("examBoard.length: " + examBoard.length);
res.render("landing", { examBoard: examBoard });
});
});

// Main startup
mongoose.connect(uri,options)
.then( () => seedDB() )
.then( () => app.listen(5858) )
.then( () => console.log('server listening') )
.catch( e => console.error(e) );

除了我们使用 .catch() 的“链接”之外,这真的只是不同。在链的末端。

请注意,在所有情况下,这里的 Promise 都是“快速失败”的,因为任何错误基本上都将在 try/catch 中被捕获。或 .catch()分别,而不试图继续。在大多数情况下,这就是您想要的,但您可以交替使用类似的 block 或 .catch() 来处理它。细粒度区域的处理程序。

设计说明

因此,提出的问题有一些非常困惑的代码,其中包含大量回调嵌套,此处展示的更现代的功能旨在“清理”并使事物再次具有功能性和可读性。您应该立即注意到理解上的显着差异。

在我看来,仍然存在问题。主要的例子是“所有问题都被添加到所有内容中”,这对于测试目的来说可能没问题,但我怀疑这是你的意图。可能有很多更有效的方法来连接这些问题,但这基本上偏离了问题的主要主题,即“等待异步完成”。

因此,部分代码有一些变化,但仅限于实现的代码实际上没有做任何事情的区域,或者至少没有做任何你可能期望的事情。 ( topicIncrementor 只会暴露给初始化为 0 的循环,并且永远不会不同)。

总体而言,这应该为您提供一个合理的指导,以了解如何以不同的方式完成事情,并了解这些任务的简洁程度,以便它们读起来完全符合它们的设计目的,而不是看起来更像“功能面”。

关于javascript - 在接受服务器请求之前等待种子数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45929426/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com