Итак, я пытаюсь создать приложение node.js-mongoose, которое предоставляет определенные конечные точки RESTful API. Вот высокоуровневая структура:
index.js
|
models
|-- user.js
|-- keys.js
controllers
|-- user.controller.js
|-- keys.controller.js
routes
|-- user.routes.js
|-- keys.routes.js
Вот образец, которому я следую для каждой отдельной детали:
myModel.js (файл модели)
import mongoose from 'mongoose';
const Schema = mongoose.Schema;
const mySchema = new Schema({
id: { type: 'String', required: true, unique: true },
});
let MyModel = mongoose.model('MyModel', mySchema);
export default MyModel;
my.controller.js (файл контроллера)
import MyModel from '../models/myModel';
const MyController = {};
// Add a new document
MyController.addNewDocument = async (req, res) => {
try {
// validate req
// save to database
await newDocument.save((err, saved) => {
if (err) {
console.info(err);
return res.status(500).send(err);
} else {
return res.status(201).json({ document: saved });
}
});
} catch (err) {
console.error('Unexpected error in addNewDocument method');
return res.status(500).send(err);
}
};
export default MyController;
my.routes.js (файл роутера)
import { Router } from 'express';
import MyController from '../controllers/my.controller';
const router = new Router();
// Add a new document
router.post('/documents', (req, res) => {
MyController.addNewDocument(req, res);
});
export default router;
Итак, у меня есть эти операции CRUD (контроллеры и маршруты) как для users, так и для keys. Требуемое поведение состоит в том, что каждый раз, когда я создаю нового пользователя, должен создаваться новый набор ключей с бизнес-логикой в функции, которая предоставляется файлом контроллера для ключа.
Вопрос: Как выполнить их по очереди? Какой должна быть правильная выкройка?
Вещи, которые я пробовал:
Вещи, которые я исследую:
Но я все еще не уверен, каким образом можно было бы добиться такого поведения.
@SivcanSingh - Конечно. функция addNewDocument выполняет операции с базой данных (обновлен комментарий '// save'). Я помещаю код, чтобы показать образец, которому я следую, с маршрутами, моделями и контроллерами. Не следует принимать за точный код. И мой вопрос, я думаю, совсем по другой теме.
Почему вы используете функцию async без ключевого слова await?
@mathakoot Сообщество поможет вам только в том случае, если они прочитали правильный код. :) Я был здесь только для этого. Даже если вы выполняете операцию db, вам нужно «дождаться» этой операции где-то в самой функции. Больше нет смысла писать async.
@SivcanSingh - Я хотел сказать, что я не пытаюсь отлаживать свой код. Я просто хотел показать образец, которому я следую с функциями контроллера и маршрутизатора. Но если это поможет, позвольте мне обновить его.
@Bergi - добавлено.
@mathakoot Я не думаю, что newDocument.save() возвращает обещание, когда вы передаете обратный вызов



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Шаблон, который я использую для очередей, использует обещания.
const promiseQueue = Promise.resolve();
function patchFile(request, response) {
promiseQueue
.then(() => updateFile(request))
.then(v => respondValid(v, response))
.catch(e => {
console.error(e);
respondError("Error patching resource", response);
});
}
У Mongoose есть хуки до и после сохранения. документы здесь
Вы можете использовать их, чтобы избежать обратных вызовов и сохранить отдельную логику.
import mongoose from 'mongoose';
const Schema = mongoose.Schema;
const keySchema = new Schema({
user: { type: Schema.Types.ObjectId, ref: 'User' },
key: { type: 'String', required: true, unique: true },
});
const userSchema = new Schema({
_id: Schema.Types.ObjectId,
name: String,
});
userSchema.post('save', (newUser) => {
// generate key
new Key({
user: newUser._id,
key: '1234567890'
}).save();
});
let User = mongoose.model('User', userSchema);
let Key = mongoose.model('Key', keySchema);
Лучший способ избежать ада обратных вызовов - использовать несколько методов, предлагаемых async, вместе с обещаниями.
async.waterfall([
function(callback){
.....
callback(null, res)
}
],
function(error, result){
.....
})
https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred
Ссылка выше показывает самый простой способ использования обещаний.
Возможно, мне что-то не хватает, но мне кажется, что вы одновременно используете обратный вызов и await. Почему бы просто не await и нормально справиться со всем?
// Add a new document
router.post('/documents', async (req, res) => {
let doc = await MyController.addNewDocument(req.body);
res.json(doc);
});
...
MyController.addNewDocument = (doc) => {
// Validate doc.
...
// Save doc (this returns a promise).
return MyModel.create(doc);
};
Мне не хватает попытки / уловки в функции async (используйте свое воображение!). Еще одна вещь, на которую стоит обратить внимание, и это только мое мнение - вы можете в конечном итоге пожалеть о передаче полных объектов req и res вашим контроллерам. Посмотрите, как я сдал только req.body. Это гарантирует, что у контроллера есть только обязанности, связанные с документом (или какой бы то ни было работой), и он ничего не знает о транзакции HTTP и других вещах, которые ему не нужны.
Что ожидает ваша асинхронная функция
addNewDocumentвmy.controller.js? И если addNewDocument предназначен для ожидания, то почему вы не ожидаете этого вmy.routes.js?