异步nodejs代码的同步样子写法样例
异步nodejs代码的同步样子写法样例
js的异步嵌套太深代码将不好看。尤其在用node的时候这种情况会大量出现。
这里用node连接redis,做一个用户注册的简单例子来说明。例如用redis做存储。我们设置一个String类型的key, seq:user这个作为自增主键ID,set类型allUser存放所有用户ID,和set类型allUserName存放所有用户名。
代码示例如下
var redis = require("redis"),
db = redis.createClient(6379, "127.0.0.1");
db.on("connect", function() {
main();
});
function main() {
insertTest();
}
var insertTest = function() {
db.incr("seq:user", function(err, userID) {
if (err) {
console.log(err);
} else {
var username = "username001";
db.set("user:" + userID + ":username", username, redis.print);
db.set("user:" + userID + ":passwd", "111111", redis.print);
db.set("username:" + username + ":uid", userID, redis.print);
db.sadd("allUserName", username, redis.print);
db.sadd("allUser", userID, function() {
console.log("OK");
});
}
});
};
逻辑很简单,先通过incr seq:user拿到自增的ID成功之后,下一步一个个保持字段信息和列表数据。
上面代码也可以改写成这个样子
var getLastUserID = function(callback) {
db.incr("seq:user", function(err, userID) {
if (!err) {
callback(userID);
}
});
};
var insertUser = function(userID) {
var username = "username001";
db.set("user:" + userID + ":username", username, redis.print);
db.set("user:" + userID + ":passwd", "111111", redis.print);
db.set("username:" + username + ":uid", userID, redis.print);
db.sadd("allUserName", username, redis.print);
db.sadd("allUser", userID, function() {
console.log("OK");
});
};
var insertTest = function() {
getLastUserID(insertUser);
};
首先要保证的是insertUser函数里面所有的插入语句顺序OK。因为我们只在最后一此插入的回调中做业务处理。中间插入语句有没有成功程序无法知晓。还有连续的同服务器交互增加了不少网络IO量。
这里的改进,使用redis的pipeline。
var insertUser = function(userID) {
var username = "username001";
var multi = db.multi();
multi.set("user:" + userID + ":username", username);
multi.set("user:" + userID + ":passwd", "111111");
multi.set("username:" + username + ":uid", userID);
multi.sadd("allUser", userID);
multi.sadd("allUserName", username);
multi.exec(function(err, replies) {
if (!err) {
console.log("OK");
}
});
};
var isUserNameExists = function(username, callback1, callback2) {
db.sismember("allUserName", username, function(err, isMember) {
if (!err && !isMember) {
callback1(username, callback2);
}
});
};
var getLastUserID = function(username, callback) {
db.incr("seq:user", function(err, userID) {
if (!err) {
callback(username, userID);
}
});
};
var insertUser = function(username, userID) {
var multi = db.multi();
multi.set("user:" + userID + ":username", username);
multi.set("user:" + userID + ":passwd", "111111");
multi.set("username:" + username + ":uid", userID);
multi.sadd("allUser", userID);
multi.sadd("allUserName", username);
multi.exec(function(err, replies) {
if (!err) {
console.log("OK");
}
});
};
var insertTest = function() {
var username = "username003";
isUserNameExists(username, getLastUserID, insertUser);
};
或者是用匿名函数的嵌套,写在一个地方
db.sismember("allUserName", username, function(err, isMember) {
if (!err) {
if (!isMember) {
db.incr("seq:user", function(err, userID) {
if (!err) {
var multi = db.multi();
multi.set("user:" + userID + ":username", username);
multi.set("user:" + userID + ":passwd", passwd);
multi.set("username:" + username + ":uid", userID);
multi.sadd("allUser", userID);
multi.sadd("allUserName", username);
multi.exec(function(err, replies) {
if (!err) {
console.log("OK");
}
});
}
});
}
}
});
两个方式阅读起来都不方便。更何况我们的示例代码逻辑并不是十分复杂,还没有加异常处理了。即便这样也是很难阅读的。
js的promise标准可以做到类似同步代码一些的写法。还有一些其他的js库也提供一些相应的同步写法。
这里介绍个叫async的库。地址在https://github.com/caolan/async
下载安装好后引入
var async = require("async");
利用async的waterfall可以指定一组函数的执行顺序,并且可以根据中间状态做流程控制。
上面的代码就可以改写成如下样子
var insertTest = function() {
var username = "username005";
async.waterfall([
function(callback) {
db.sismember("allUserName", username, callback);
},
function(isMember, callback) {
if (!isMember) {
db.incr("seq:user", callback);
} else {
callback(new Error("username has exist"), null);
}
},
function(userID, callback) {
var multi = db.multi();
multi.set("user:" + userID + ":username", username);
multi.set("user:" + userID + ":passwd", "111111");
multi.set("username:" + username + ":uid", userID);
multi.sadd("allUser", userID);
multi.sadd("allUserName", username);
multi.exec(function(err, replies) {
if (!err) {
callback(null, "OK");
} else {
callback(new Error("save data fail"), null);
}
});
}
], function (err, result) {
console.log(err);
console.log(result);
});
};
它会按照定义好的函数列表挨个执行,并且上一个函数执行的结果很方便地传入到下一个函数中做判断。上例代码中因为js约定的机制,回调第一个参数err,第二个是正确结果。所以传递的过程都不需要自己写。
这样改写之后不光看起来清楚,流程控制起来也更加方便。例如如果用户名重复的错误,或者是保存数据失败的错误发生了,或者是全部调用成功了。都可以在最后的统一结果处理函数中处理掉。
使用async.waterfall做流程控制个人感觉比用promise库要简单方便。
异步nodejs代码的同步样子写法样例的更多相关文章
- mocha框架下,异步测试代码错误造成的问题----用例超时错误
今天用抹茶(mocha)做个测试,发现有一个测试项目总是超时: describe("DbFactory functions",function(){ it("query ...
- Python代码转c#部分参考样例
最近在做一部分Pyhton代码转c#代码的工作,以下案例亲自都测试过,现整理出来希望对有帮助的同学提供参考: Python | C# *:first-child{margin-top:0 !impor ...
- C++ Primer中文本查询演示样例Query的实现
近期在看C++ Primer复习C++的语法,看到书中15.9章中的文本查询演示样例时,认为设计得非常不错,于是便动手照着实现了一个,改动了非常久最终执行成功了,从中也学习到了非常多的语法.以下把实现 ...
- Python Web框架Tornado的异步处理代码演示样例
1. What is Tornado Tornado是一个轻量级但高性能的Python web框架,与还有一个流行的Python web框架Django相比.tornado不提供操作数据库的ORM接口 ...
- javascript es6 Promise 异步同步的写法(史上最简单的教程了)
1 来个简单的例子 var p = new Promise(function(resolve, reject){ //做一些异步操作 setTimeout(function(){ console.lo ...
- Ext JS学习第十六天 事件机制event(一) DotNet进阶系列(持续更新) 第一节:.Net版基于WebSocket的聊天室样例 第十五节:深入理解async和await的作用及各种适用场景和用法 第十五节:深入理解async和await的作用及各种适用场景和用法 前端自动化准备和详细配置(NVM、NPM/CNPM、NodeJs、NRM、WebPack、Gulp/Grunt、G
code&monkey Ext JS学习第十六天 事件机制event(一) 此文用来记录学习笔记: 休息了好几天,从今天开始继续保持更新,鞭策自己学习 今天我们来说一说什么是事件,对于事件 ...
- java 线程、线程池基本应用演示样例代码回想
java 线程.线程池基本应用演示样例代码回想 package org.rui.thread; /** * 定义任务 * * @author lenovo * */ public class Lift ...
- 18.1利用socket .io 实现 editor间代码的同步
首先,我们想实现在同一个页面editor 大家同时编辑 同步 所以能 我们需要这个url 作为我们 session id 或者叫聊天室的roomid 或者 反正就是保证他们在同一个list里面 就是 ...
- 10分钟理解Android数据库的创建与使用(附具体解释和演示样例代码)
1.Android数据库简单介绍. Android系统的framework层集成了Sqlite3数据库.我们知道Sqlite3是一种轻量级的高效存储的数据库. Sqlite数据库具有以下长处: (1) ...
随机推荐
- 转: 将Eclipse代码导入到AndroidStudio的两种方式 ,测试了方法2,成功。
蛋疼,不知道为什么我的eclipse的logcat总是莫名其妙的显示一堆黄色字体的字,看不懂的那种,如下图: 然后查了一下资料,说可能是adt版本太低,手机系统太高. 然后本来想升级adt,但是各种折 ...
- 添加ASP.NET网站资源文件夹
ASP.NET应用程序包含7个默认文件夹,分别为Bin.APP_Code.App_GlobalResources.App_LocalResources.App_WebReferences.App_Br ...
- (转)python time模块和datetime模块详解
python time模块和datetime模块详解 原文:http://www.cnblogs.com/tkqasn/p/6001134.html 一.time模块 time模块中时间表现的格式主要 ...
- ORACLE迁移GP实践
最近在做oracle到greenplum的迁移实践,步骤如下: 1. 使用ora2pg实现Oracle的数据结构迁移到GP的实现过程 2. Oracle的数据迁移到GP的实现过程 1. ora2p ...
- bug缺陷级别定义
缺陷定义: 出现以下缺陷测试定义为致命 bug l 系统无响应处于死机状态. l 点击某个菜单后出现“The page cannot be displayed”或者返回异常错误. l 进行某 ...
- 【Nginx】关于域名转发proxy_pass
在配置nginx的时候,有一个需求,访问m.XXX.com的时候,需要实际访问www.YYY.com/m,并且域名不能发生变化. 达成这个需求有两种做法: 第一种就是301跳转,使用rewrite来跳 ...
- 记一次数据、逻辑、视图分离的原生JS项目实践
一切的开始源于这篇文章:一句话理解Vue核心内容. 在文章中,作者给出了这样一个思考: 假设现在有一个这样的需求,有一张图片,在被点击时,可以记录下被点击的次数. 这看起来很简单吧, 按照上面提到到开 ...
- C#基本语法 - .Net 4.0 之 Dynamic 动态类型
一..net4.0主要新特性 .Net4.0在.Net3.5基础上新增的主要特性有:可选参数.命名参数和Dynamic.具体请阅生鱼片的这篇博文.这里我们着重讲解C#4.0的Dynamic特性,对 ...
- Query performance optimization of Vertica
Don't fetch any data that you don't need,or don't fetch any columns that you don't need. Because ret ...
- nltk模块
1. nltk简介 http://www.nltk.org 2. nltk能做什么? 2.1 搜索文本 单词搜索 相似词搜索 相似关键词识别 词汇分布图 生成文本 from nltk.book imp ...