Last active
March 3, 2017 08:05
-
-
Save stableShip/0b3deabd159f2ea2ff9889313cf8bd7b to your computer and use it in GitHub Desktop.
Node编程规范
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Node编码规范 | |
## 注释 | |
使用代码注释的目的是用文字说明代码的作用(即为什么要用编写该代码,而不是如何编写),说明何时可能出错和为什么出错。通常在编写代码前进行注释,在要注释的代码前书写注释。 | |
1. 注释可以采用`/*注释内容*/ `和`//注释内容`两种注释符号,涉及到多行注释时采用前者的方式。 | |
2. 对于一行代码的注释可放在前一行及本行上,不允许放在下一行,更不允许在一行语句的中间加入注释。 | |
3. “路由” 注释: | |
``` | |
/** | |
* @api {请求方法: get|post} 请求路由名称 | |
* @apiVersion api适用版本 | |
* @apiName 请求唯一名称 | |
* @apiGroup api所属组 | |
* @apiDescription api描述 | |
* @apiHeader {参数类型} 请求头参数名称 请求头参数值 | |
* @apiHeader {String} accept application/json;charset=utf-8 | |
* | |
* @apiParam {参数类型} 请求参数名称 请求参数值 | |
* @apiParam {Number} token 登陆凭证 | |
* | |
* @apiSuccess {返回值类型} 返回值名陈 返回具体值 | |
* @apiSuccess {Number} err 错误码:`0`-成功,`!0`-失败 | |
* | |
*/ | |
``` | |
api注释语法参照: http://apidocjs.com/ | |
4. 函数注释: | |
``` | |
/** | |
* 方法的功能描述 | |
* @param args 参数的含义 | |
* @return 返回的数据格式 | |
*/ | |
``` | |
5. 局部变量、字段、属性的注释:主要变量必须有注释。 | |
6. 不必每行都加注释,在3~10行左右的段落做注释要好于每行都做注释。 | |
7. 代码删除,不要使用注释的形式, 直接进行删除. | |
----- | |
## 代码排版格式 | |
要上传时使用webstorm选择要提交的代码, 进行格式化后再进行上传. | |
1. 每一个开始括弧在源程序中紧跟逻辑代码,结束的括弧需要独占一行。如: | |
``` | |
for (int i = 0; i < 10; i++) { | |
//逻辑代码 | |
} | |
``` | |
2. 对于if,if-else,while,for,switch,case这些语句都必须使用{}扩起来。不要只有一行就不使用{} | |
``` | |
if (true) { | |
console.log('winning'); | |
} | |
``` | |
3. 代码长度 | |
每行只能有一个语句 | |
每行代码最多不得操作120个字 | |
每个函数方法内代码长度尽量控制到不超过70行。 | |
4. 使用标准回调 | |
Node 的异步回调函数的第一个参数应该是错误指示 | |
``` | |
function cb(err, data) {...} | |
``` | |
5. 立即返回 | |
对 满足退出条件的立即返回, 不要使用if, else进行处理 | |
Right: | |
``` | |
if(true){ | |
return true; | |
} | |
// 执行false处理 | |
``` | |
Wrong: | |
``` | |
if(false){ | |
// 执行false处理 | |
} | |
return true; | |
``` | |
6. 大括号的使用约定 | |
如果是大括号内为空,则简洁地写成{}即可,不需要换行;如果 | |
是非空代码块则: | |
* 左大括号前不换行 | |
* 左大括号后换行 | |
* 右大括号前换行 | |
* 右大括号后还有else等代码则不换行;表示终止右大括号后必须换行 | |
----- | |
## 命名规范 | |
1. 文件命名 | |
文件命名采用下划线命名法 | |
``` | |
java_script.js | |
``` | |
2. 类 | |
采用大驼峰命名法, 尽量避免使用单词的缩写,除非它的缩写已经广为人知,如HTTP | |
``` | |
// 大驼峰 | |
JavaScript | |
``` | |
3. 方法 | |
采用小驼峰命名法, 尽量避免使用单词的缩写, 异步方法必须添加Async后缀. | |
``` | |
// 小驼峰 | |
javaScript | |
// 同步方法 | |
set | |
// 异步方法 | |
setAsync | |
``` | |
4. 变量 | |
采用小驼峰命名法, 变量必须起有意义的名字,使其他组员可以很容易读懂变量所代表的意义,变量命名可以采用同义的英文命名,可使用几个英文单词,第一个单词首字母小写,其他单词首字母大写。 | |
``` | |
// 小驼峰 | |
userName; | |
``` | |
5. 常量 | |
所有常量名均全部大写,单词间以‘_’隔开 | |
避免在程序中直接出现常数,使用超过一次的应以常量定义替代。 | |
``` | |
{ | |
JAVA_SCRIPT: 1 | |
} | |
``` | |
6. 数据库字段 | |
所有字段使用小驼峰进行命名 | |
``` | |
// 小驼峰 | |
javaScript; | |
``` | |
## 文件规范 | |
1. 所有模块分为 数据库表结构层`schema`(lib文件夹), 数据库服务层`service`(model文件夹), 路由层'router'(router文件夹), | |
2. 数据库表结构层`schema`(lib文件夹), 定义数据库表数据结构 | |
3. 数据库服务层`service`(model文件夹), **所有和数据库交互的, 都定义在该层, 必须定义操作基础方法(增删改查)**, 其他方法自行扩展: | |
* 获取模块列表方法 getXXXListByCondictionAsync , conditon包含查询的基础条件, 示例: | |
``` | |
/** | |
* 根据条件查询banner列表 | |
* @param condition | |
* @returns {*} | |
*/ | |
static getBannerListByCondictionAsync(condition) { | |
return co(function*() { | |
yield BannerService.updateBannerStatusAsync(); | |
var limit = condition.rows && parseInt(condition.rows) || 10; | |
var pages = condition.pages && parseInt(condition.pages) || 1; | |
var skip = (pages - 1) * limit; | |
var query = {}; | |
if (condition.name) { | |
query.name = new RegExp(name); | |
} | |
if (condition.begin) { | |
var begin = new Date(condition.begin); | |
begin = new Date(begin.getFullYear(), begin.getMonth(), begin.getDate()); | |
query.startdatetime = {$gte: begin}; | |
} | |
if (condition.end) { | |
var end = new Date(condition.end); | |
end = new Date(end.getFullYear(), end.getMonth(), end.getDate() + 1); | |
query.enddatetime = {$lte: end}; | |
} | |
if (condition.status && !_.isEmpty(condition.status) && _.isArray(condition.status)) { | |
var status = _.map(condition.status, (status) => { | |
return parseInt(status) | |
}); | |
query.status = {$in: status}; | |
} | |
var banners = yield model.banner.aggregate() | |
.match(query) | |
.sort({sort: -1}) | |
.skip(skip) | |
.limit(limit) | |
.project({ | |
name: 1, | |
bannerImage: {$concat: ["http://", config.ALIOSS.imageHost, "/", "$bannerImage"]}, | |
startDateTime: 1, | |
endDateTime: 1, | |
status: 1, | |
jumpType: 1, | |
sort: 1, | |
jumpTo: 1, | |
businessType: 1, | |
jumpParams: 1, | |
eduit: 1, | |
makeDate: 1, | |
editDate: 1 | |
}); | |
return banners; | |
}) | |
} | |
``` | |
* 获取模块列表总数 getXXXListCountByCondictionAsync, 示例: | |
``` | |
/** | |
* 根据条件查询banner列表总数 | |
* @param condition | |
* @returns {*} | |
*/ | |
static getBannerListCountByCondictionAsync(condition) { | |
return co(function*() { | |
var query = {}; | |
if (condition.name) { | |
query.name = new regexp(name); | |
} | |
if (condition.begin) { | |
var begin = new date(condition.begin); | |
begin = new date(begin.getfullyear(), begin.getmonth(), begin.getdate()); | |
query.startdatetime = {$gte: begin}; | |
} | |
if (condition.end) { | |
var end = new date(condition.end); | |
end = new date(end.getfullyear(), end.getmonth(), end.getdate() + 1); | |
query.enddatetime = {$lte: end}; | |
} | |
if (condition.status && !_.isEmpty(condition.status) && _.isArray(condition.status)) { | |
var status = _.map(condition.status, (status) => { | |
return parseInt(status) | |
}); | |
query.status = {$in: status}; | |
} | |
var count = yield model.banner.count(query); | |
return count; | |
}) | |
} | |
``` | |
* 更新模块某条数据 updateXXXAsync, 示例: | |
``` | |
/** | |
* 更新banner | |
* @param banner | |
* @returns {*} | |
*/ | |
static updateBannerAsync(banner) { | |
return co(function*() { | |
var id = ObjectId(banner._id); | |
// 删除banner空值 | |
for (var key in banner) { | |
if (_.isUndefined(banner[key]) || _.isNull(banner[key])) { | |
delete banner[key]; | |
} | |
} | |
var result = yield model.banner.findOneAndUpdate({_id: id}, banner, {new: true}); | |
return result; | |
}) | |
} | |
``` | |
* 删除模块某条记录 deleteXXXByIdAsync, 示例: | |
``` | |
/** | |
* 根据id删除某个banner | |
* @param id | |
* @returns {*} | |
*/ | |
static deleteBannerByIdAsync(id) { | |
return co(function*() { | |
id = ObjectId(id); | |
var banner = yield model.banner.remove({_id: id}); | |
return banner; | |
}) | |
} | |
``` | |
* 增加模块一条数据, createXXXAsync 示例: | |
``` | |
/** | |
* 创建banner | |
* @param banner | |
* @returns {*} | |
*/ | |
static createBannerAsync(banner) { | |
return co(function*() { | |
if (!banner.sort) { | |
var banners = yield model.banner.find().sort({sort: -1}).limit(1); | |
banner.sort = !_.isEmpty(banners) && banners[0].sort + 1 || 1; | |
} | |
// 删除banner空值 | |
for (var key in banner) { | |
if (_.isUndefined(banner[key]) || _.isNull(banner[key])) { | |
delete banner[key]; | |
} | |
} | |
var result = yield model.banner.create(banner); | |
return result; | |
}) | |
} | |
``` | |
4. 路由层'router'(router文件夹), 调用service层提供的方法, 所有涉及数据库查询**都不要写在router层.** | |
----- | |
## 路由定义规则 | |
1. 在 路由层'router'(router文件夹) index.js文件夹, 定义不同版本的路由索引, 如: | |
`app.use('/v4', v4_route);` | |
2. 在各个版本index.js文件夹中, 定义该版本包含的路由, **所有的路由定义都在index.js文件中, 不要再继续在下一层传播, 方便查阅**, 如: | |
`router.use("/admin/banner", require('./admin/banner'));` | |
3. 每个不同模块尽可能使用单独一个文件进行相应路由编写, 如: | |
``` | |
// banner.js | |
router.post("/findOne", ...) | |
router.post("/list", ...) | |
router.post("/delete", ...) | |
router.post("/update", ...) | |
``` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment