我在使用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: '正确'};
问题:
在实际项目中, 是如何解决这种情况的? 我查了数据库, 貌似还没有同步的解决方案出现?
我没有使用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);
});
};
处理过程的确是异步处理,对于大多数语言/框架来说,默认情况下都是同步处理,需要异步的时候开一个线程进行异步处理,所以异步的数量是很容易控制的。然而 Node 的实现有点不一样,由于 JavaScript 是单线程程序,比较耗时的操作为了阻止阻碍都会采用异步处理。
异步处理就一定涉及到消息通知,或者说线程间的交互。在 Node 中是通过回调来实现的(因为是单线程的异步……纠结),或者说得高大上一点,是通过观察者模式来实现的。对于 ES5 来说,使用回调嵌回调是最直接的方式。当然随着 Node 的使用越来越广,出现了不少的库用来解决这个问题,统称为 Promise 库吧。很显然,ECMA 也意识到了这个问题,所以 ES6/ES2015 中直接内置了 Promise 实现。
调用
虽然用 Promise 好多了,但是写起来还是比较繁琐,尤其是使用的库没使用 Promise 封装的时候,要自己去改造是件痛苦的事情。
所以 ES7 准备实现 async/await,把异步调用同步化(仅指写法上同步化,并非真正的同步),另外有一些库,比如 KOA,也尝试通过 generator 来实现异步链,想了解可以参考 KOA 的文档。