search

Home  >  Q&A  >  body text

express - node.js中操作mongodb, 如何解决异步的问题?

我在使用node.js + express + mongodb做一个英语课堂测试系统, 其中有一个学生管理界面. 新增一个学生, 有以下字段: name(名称), age(年龄), grade(年级)等, 于是我封装了一个判断函数, 用于判断前端所传递的数据是否有误:

  // 检查所传入的数据是否有效
  function check_info(_id, name, age, grade) {
    if ("" == name) {
      return {status: false, msg: '名称不可为空'};
    }
    age = parseInt(age);
    grade = parseInt(grade);
    if (isNaN(age)) {
      return {status: false, msg: '年龄必须为整数'};
    }
    if (isNaN(grade)) {
      return {status: false, msg: '年级必须为整数'};
    }
    console.log("1");
    if (_id) {
      collection.find({_id: _id, name: name}).count(function (err, count) {
        if (1 != count) {
          return {status: false, msg: '编辑情况下, 名称不可更改!'};
        }
      });
    } else {
      console.log("2");
      collection.find({name: name}).count(function (err, count) {
        console.log("3");
        if (0 != count) {
          return {status: false, msg: '新增情况下, 数据库中已经存在此名称!'};
        }
      });
    }
    console.log("4");
    return {status: true, msg: '正确'};
  }

在这里, 很明显, 由于find数据库时候, 采用的是异步操作, 导致永远返回{status: true, msg: '正确'};

问题:

  1. 在实际项目中, 是如何解决这种情况的? 我查了数据库, 貌似还没有同步的解决方案出现?

  2. 我没有使用mongoose, 使用的是mongodb的本身api:

var express = require('express');
var router = express.Router();
var init = function (callback) {
var MongoClient = require('mongodb').MongoClient;
  var url = 'mongodb://localhost:27017/test_system';
  MongoClient.connect(url, function (err, db) {
    var collection = db.collection('students');
    callback(collection);
  });
};
迷茫迷茫2787 days ago419

reply all(4)I'll reply

  • 怪我咯

    怪我咯2017-04-17 15:40:05

    The processing process is indeed asynchronous. For most languages/frameworks, it is processed synchronously by default. When asynchronous processing is required, a thread is opened for asynchronous processing, so the number of asynchronous processing is easy to control. However, the implementation of Node is a bit different. Since JavaScript is a single-threaded program, more time-consuming operations are processed asynchronously to avoid obstructions.

    Note: Single-threaded asynchronous operations are awkward to describe. There are a lot of introductions to the principles. I directly understand that: the main thread is responsible for the UI, and all other things must be done asynchronously on other threads. . Android is developing in this direction and already requires network operations to not be performed on the main thread, so this approach is understandable.

    Asynchronous processing must involve message notification, or interaction between threads. In Node, it is implemented through callbacks (because it is single-threaded asynchronous... tangled), or to put it more elegantly, it is implemented through the observer pattern. For ES5, using callbacks to embed callbacks is the most straightforward way. Of course, as Node is used more and more widely, many libraries have emerged to solve this problem, collectively called Promise libraries. Obviously, ECMA is also aware of this problem, so Promise implementation is built directly into ES6/ES2015.

    function init() {
        var MongoClient = require("mongodb").MongoClient;
        var url = "mongodb://localhost:27017/test_system";
        return new Promise((resolve, reject) => {
            MongoClient.connect(url, function(err, db) {
                if (err) {
                    throw err;  // 和调用 reject(err) 效果类似
                }
                var collection = db.collection("students");
                resolve(collection);
            });
        });
    }
    
    function asyncCheckInfo(collection, _id, name, age, grade) {
        return new Promise((resolve, reject) => {
            if ("" == name) {
                reject({ status: false, msg: "名称不可为空" });
                return;
            }
    
            // ....
            // 省略的这部分代码的改造与上面类似
            // ....
    
            // 下面是两个异步调用,注意异步调用结束(即在回调中)一定要调用 resolve 或者 reject
            // 为了统一处理,定义一个局部函数
            function deal(err, isError, errMsg) {
                if (err) {
                    reject({ status: false, msg: err.message });
                    return;
                }
    
                if (isError) {
                    reject({ status: false, msg: errMsg });
                    return;
                }
    
                resolve({ status: true, msg: "正确" });
            }
    
            if (_id) {
                collection.find({ _id: _id, name: name }).count(function(err, count) {
                    deal(err, 1 !== count, "编辑情况下, 名称不可更改!");
                });
            } else {
                collection.find({ name: name }).count(function(err, count) {
                    deal(err, 0 !== count, "新增情况下, 数据库中已经存在此名称!");
                });
            }
    
            // 上面所有分支都已经有 resolve 或 reject 调用了,搞定
        });
    }

    Call

    init().then(connection => {
        return asyncCheckInfo(connection, _id, name, age, grade);
    }).then(jo => {
        // asyncCheckInfo 中通过 resolve 给的对象
        // jo.status === true
    }, jo => {
        // asyncCheckInfo 中通过 reject 给的对象
        // jo.status === false
        console.log(jo.msg);
    });

    Although using Promise is much better, it is still relatively cumbersome to write, especially when the library used is not packaged with Promise, it is painful to modify it yourself.

    So ES7 is preparing to implement async/await to synchronize asynchronous calls (only refers to synchronization in writing, not real synchronization). Some libraries, such as KOA, also try to implement asynchronous chains through generators. If you want to know more, you can Refer to KOA's documentation.

    reply
    0
  • PHP中文网

    PHP中文网2017-04-17 15:40:05

    1.asyncjs
    2.bluebird
    3. Wait for node 7.X to be released and use await/async

    reply
    0
  • PHP中文网

    PHP中文网2017-04-17 15:40:05

    This problem may be difficult to get used to when you first come into contact with node.js. Yes, it does execute like an assembly line in your mind, but the default method is only a callback function (you give it a box and let it execute After finishing, put what you want in this box), however, the callback function will not wait for it to finish executing before executing anything else, so you cannot get the results sequentially. When your query has been executed The next sentence is executed immediately, until the last sentence, so the result is the same every time. Therefore, you need to perform the next step in the callback function, but in the future you will find that too many steps will be deeply nested, and you will learn about promise+generator and async+await.

    If you need to return, you can accept a callback function, and then call this function to transfer your data.

    Let me visualize your example for you.

    Your father gave you a pot and asked you to buy soy sauce. You asked your brother to buy it and put it in your pot. Your query is the process of asking your brother to make soy sauce. When he comes back after making the sauce, the callback function is executed. When it's done, then you take the next step. This process should be in your mind, but you just asked your brother to make soy sauce, and then handed the pot to your dad. Of course, the oil pot is empty every time.

    Without a computer, I can’t write code for you. The code should be the most intuitive.

    reply
    0
  • 天蓬老师

    天蓬老师2017-04-17 15:40:05

    Define an object to store the returned data, and then return this object to the front end

    reply
    0
  • Cancelreply