express - node.js中操作mongodb, 如何解决异步的问题?
迷茫
迷茫 2017-04-17 15:38:05
0
4
370

我在使用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); }); };
迷茫
迷茫

业精于勤,荒于嬉;行成于思,毁于随。

全部回覆 (4)
刘奇

处理过程的确是异步处理,对于大多数语言/框架来说,默认情况下都是同步处理,需要异步的时候开一个线程进行异步处理,所以异步的数量是很容易控制的。然而 Node 的实现有点不一样,由于 JavaScript 是单线程程序,比较耗时的操作为了阻止阻碍都会采用异步处理。

备注:单线程的异步操作,咋个说都别扭,看原理介绍一大堆,我直接理解为:主线程负责 UI,要干所有其它事情都必须在其它线程上异步操作。Android 在向这个方向发展,已经要求网络操作等不能在主线程进行了,所以这种方式还是可以理解的。

异步处理就一定涉及到消息通知,或者说线程间的交互。在 Node 中是通过回调来实现的(因为是单线程的异步……纠结),或者说得高大上一点,是通过观察者模式来实现的。对于 ES5 来说,使用回调嵌回调是最直接的方式。当然随着 Node 的使用越来越广,出现了不少的库用来解决这个问题,统称为 Promise 库吧。很显然,ECMA 也意识到了这个问题,所以 ES6/ES2015 中直接内置了 Promise 实现。

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 调用了,搞定 }); }

调用

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

虽然用 Promise 好多了,但是写起来还是比较繁琐,尤其是使用的库没使用 Promise 封装的时候,要自己去改造是件痛苦的事情。

所以 ES7 准备实现 async/await,把异步调用同步化(仅指写法上同步化,并非真正的同步),另外有一些库,比如 KOA,也尝试通过 generator 来实现异步链,想了解可以参考 KOA 的文档。

    洪涛

    1.asyncjs
    2.bluebird
    3.等node 7.X发布 用 await/async

      洪涛

      这个问题可能是刚接触node.js的时候很难习惯的问题,是的,在你心中确实像流水线一样在执行,但是默认的方式只有回调函数(你给他一个盒子让他在执行完以后把你想要的东西放在这个盒子里),然而回调函数是不会先等待他执行完后再执行别的,所以你顺序的形式获得结果是不行的,当你查询已经执行的时候马上就执行了下一句,直到最后一句,所以每次结果都一样。因此你需要在回调函数里执行下一步操作,但是以后你就会发现步骤太多就会嵌套很深,就会了解到promise+generator以及async+await了。

      如果你需要返回,可以接受一个回调函数,你再调用这个函数把你的数据传出去。

      你这个例子我给你形象化吧。

      你爸爸给你一个壶要你买酱油,你让弟弟去买来了一装在你的壶里,你这个查询就是让你弟弟去打酱油的过程,他打完回来就是回调函数执行完的时候,然后你再执行下一步,你心里应该是这个过程了,但是你刚让你弟弟去打酱油,接着就把壶交给你爸了,当然每次油壶都是空的咯。

      没有电脑在身边,也不能给你写代码了,代码应该是最直观的。

        Peter_Zhu

        定义一个对象存储返回的数据,然后返回这个对象给前端

          最新下載
          更多>
          網站特效
          網站源碼
          網站素材
          前端模板
          關於我們 免責聲明 Sitemap
          PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!