回到3个月刚毕业到单位的时候,三天熟悉代码的时间不算多也不算少。拿到诸如如下的操作数据库的代码:
var user_table = dbconn.createtable(dbconn.usertablename, dbconn.user_table, function (create_result) {
userdataarray.forEach(function(userdata) {
var querycondition = {
"username": userdata.username
};
dbconn.querytable(user_table, querycondition, function (queryresult) {
if (queryresult.length > 0) {
var sendresult = {
status:"user fail",
username:username
};
res.json(sendresult);
} else {
dbconn.insertdbdata(user_table, userdata, function (result) {
var userstr = {
"username": username,
"group": group
};
var result1 = {
userid: result.dataValues.id,
uname: result.dataValues.username
};
console.log("result1 =",JSON.stringify(result1))
userresult.push(result1);
}, function (err) {
var sendresult = {
status:"alloc fail"
};
var sendresult = {
status:'success',
result:userresult
};
res.json(sendresult);
console.error(err);
LogFile.error(err);
});
}
})
}, function (err) {
var sendresult = {
status:"alloc fail"
};
res.json(sendresult);
console.erroror(err);
LogFile.error(err);
});
});
刚开始就是这样让我学习node和sequlize操作mysql的,现在看起来真的是很不优雅。当时写着写着还感觉挺简单不就是回调套回调嘛,sql还是封装好的,我什么都不用干呀。但是就是这种状态下写着写着我开始发现回调执行时我想对sendresult进行些操作再返回简直妄想,因为每次都是undefined。这个时候我开始有些厌烦异步了,没错!就是厌烦,我会暗自吐槽这种我不理解的机制而不是努力掌握这种机制。其实每次到了这种时候我们只需要转换思路或者与人讨论再或者不耻下问即可,根据与公司的另一位搞后台的同事讨论了一番得到了一个“阀”字,也就是说既然不能按照异步的方式去处理那就在处理前建立一个阀门,来控制数据。所以有了下面的改进代码:
var user_table = dbconn.createtable(dbconn.usertablename, dbconn.user_table, function (create_result) {
userdataarray.forEach(function(userdata) {
var querycondition = {
"username": userdata.username
};
dbconn.querytable(user_table, querycondition, function (queryresult) {
if (queryresult.length > 0) {
var sendresult = {
status:"user fail",
username:username
};
res.json(sendresult);
} else {
dbconn.insertdbdata(user_table, userdata, function (result) {
var userstr = {
"username": username,
"group": group
};
var result1 = {
userid: result.dataValues.id,
uname: result.dataValues.username
};
console.log("result1 =",JSON.stringify(result1))
userresult.push(result1);
if(num == userdataarray.length-1){
var sendresult = {
status:'success',
result:userresult
};
res.json(sendresult);
}
num++;
}, function (err) {
var sendresult = {
status:"alloc fail"
};
res.json(sendresult);
console.error(err);
LogFile.error(err);
});
}
})
}, function (err) {
var sendresult = {
status:"alloc fail"
};
res.json(sendresult);
console.erroror(err);
LogFile.error(err);
});
});
上述代码中的“阀”也就是 if(num == userdataarray.length-1)这句话,在回传前控制数据,不要让其得到undefinded值。在完成了这一步操作后,我理解了回调的“坑爹”之处。
在下来的日子里我在crud之前,都得先createtable然后再view/update/delete/add,终于在一周前我忍受不了这么累赘的代码。回想起以前看过的一篇关于介绍es6新特性的文章中被誉为异步神器的Promise大法。我抱着试试的心态去网上搜索文章,因为使用的是sequlize所以我先查了其官方api,只得到了其每一个返回的对象均是封装好的promise对象,但是用法丝毫未提及,然后去查promise api,大概了解如何创建和他有哪些方法,感觉还是差了点,然后就去搜了各种关于promise实战的文章,然后尝试修改如下代码:
var gettable = dbconn.createtable(dbconn.vmtablename, dbconn.vm_table, function (result) {
var vmquerycondition = {
group: groupname
};
var data = dbconn.querytable(gettable, vmquerycondition, function (vmresult) {
var grouptable = dbconn.createtable(dbconn.vmgrouptablename, dbconn.vmgroup_table, function (result) {
var groupquerycondition = {
parent: groupname
};
var data = dbconn.querytable(grouptable, groupquerycondition, function (groupresult) {
var vmdataarray = [];
for(var i=0;i
修改后如下:
var vmTable = dbconn.createtable1(dbconn.vmtablename, dbconn.vm_table);
var vmgroupTable = dbconn.createtable1(dbconn.vmgrouptablename, dbconn.vmgroup_table);
var co1 = dbconn.querytable1(vmTable, vmquerycondition);
var co2 = dbconn.querytable1(vmgroupTable, groupquerycondition);
console.log('promise start.',vmTable,vmgroupTable);
var res_1 = res1;
Promise
.then(dbconn.querytable1(vmTable , vmquerycondition))
.then(function(res1){
dbconn.querytable1(vmgroupTable, groupquerycondition)
})
.then(function(res2){
for(){//对res1与res2这俩个数据结果集进行操作...}
})
很丑陋但是很同步,就是想单纯的在拿到res1后再拿res2,然后对二者进行操作,后果可想而知。res1拿不到,我开始反思自己,是不是只停留在网络上相互抄袭的栗子之中而忘记了promise本身是干什么的,以及他出现的意义。每当迷茫的时候,你需要看书来学习。秉承着一学到底的精神,搜了很多书籍中关于promise的部分知识。但是最让我受用的还是《你不懂的JS(中卷)》关于promise和回调讲解的三部分,里面的阀概念和前面所用的
if(num == userdataarray.length-1)不谋而合,只不过里面是判断undefined控制if (x != undefined) ,细细研读了一遍后,改用promise.all()方法。最终修改代码如下:
var vmTable = dbconn.createtable1(dbconn.vmtablename, dbconn.vm_table);
var vmgroupTable = dbconn.createtable1(dbconn.vmgrouptablename, dbconn.vmgroup_table);
var co1 = dbconn.querytable1(vmTable, vmquerycondition);
var co2 = dbconn.querytable1(vmgroupTable, groupquerycondition);
console.log('promise start.',vmTable,vmgroupTable);
var resultdata;
Promise
.all([co1,co2])
.then(function(res){
console.log('promise ing:',res[0]);
console.log('promise ing:',res[1]);
var vmdataarray = [];
for(var i=0;i
成功解决,这样子的话,每次所需要建立的表我只需要写在单独的文件中每次在代码开头require导入就行,这样也避免了“回调深渊”的问题。找到可优化的点刨根问底,知道自己要什么,然后慢慢摸索出一套属于自己的怎么做的方法即可。
主要参考文献: 你不懂JS系列