node.js多个回调/回调串行执行

时间:2018-07-17 05:46:45

标签: javascript node.js ecmascript-6 callback promise

因此,我试图创建一个暴露某些RESTful API端点的node.js-mongoose应用程序。这是一个高级结构:

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.log(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;

因此,对于userskeys我都有这些CRUD操作(控制器和路由)。所需的行为是,每次创建新用户时,都应使用密钥的控制器文件公开的功能中的业务逻辑来生成一组新的密钥。

问题: 我如何一个接一个地执行它们?正确的模式应该是什么?

我尝试过的事情:

  1. 回调地狱
  2. 使用res.redirect等在控制器功能内调用其他端点。

我探索的事情

  1. 承诺
  2. 多个回调

但是我仍然不确定实现上述行为的正确方法。

4 个答案:

答案 0 :(得分:2)

猫鼬有前和后保存钩子。 docs here

您可以使用它们来避免回调并保持逻辑分离。

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);

答案 1 :(得分:0)

我用于队列的模式使用promise。

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);
  });
}

答案 2 :(得分:0)

避免回调地狱的最好方法是使用async提供的几种方法以及promise。

async.waterfall([
  function(callback){
    .....
    callback(null, res)
  }
 ],
 function(error, result){
 .....
})

https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred

上方链接显示了使用承诺的最简单方法

答案 3 :(得分:0)

我可能丢失了一些内容,但是对我来说,您似乎同时使用了回调和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);

};

我缺少异步功能中的try / catch(用你的想象力!)。需要指出的另一件事,这只是我的观点–您可能最终后悔将完整的reqres对象传递给控制器​​。了解我如何仅传递req.body。这样可以确保控制器仅负责与文档相关联的责任(或其职责是什么),并且不了解HTTP事务和其他一切。