0%

想干活的时候先上npm找找

鲁迅

前言

有两个实现定时任务的类库,为什么cron下载多,可能因为短,就用这个

类库 当周下载量
node-schedule 192699
cron 499,742

安装

  • 当然是用ts开发
$ npm i cron
$ npm i @types/cron

简单测试

基础使用

  • 每秒都输出当前的时间
  • 构建job通过start方法启动
import { CronJob, CronTime } from 'cron'

let job = new CronJob('* * * * * *', () => {
const d = new Date()
console.log(d.toLocaleString(undefined, {
hour12: false
}))
})
job.start()

修改时间参数

  • 保存job的句柄,在其他地方修改任务的时间设置
  • 先用stop停止之前的任务,在用start开始
import { CronJob, CronTime } from 'cron'

let job = new CronJob('* * * * * *', () => {
const d = new Date();
console.log(d.toLocaleString(undefined, {
hour12: false
}));
})
job.start()

....
干了很多事情了
....

job.stop()
job.setTime(new CronTime('*/10 * * * * *'))
job.start()

时间的校验

  • 一般设置的触发条件可能要等很久,所以要有一个检测
  • 不然等到触发时间了,结果无效的,就呵呵呵了

获取下次触发的时间

job.nextDate()

获取接下来5次触发的时间

job.nextDates(5)

cron表达式

标识含义

* * * * * *
  1. Seconds
  2. Minutes
  3. Hours
  4. Day-of-Month
  5. Month
  6. Day-of-Week

参数设置

Seconds (秒) :可以用数字0-59 表示,
Minutes(分) :可以用数字0-59 表示,
Hours(时) :可以用数字0-23表示,
Day-of-Month(天) :可以用数字1-31 中的任一一个值,但要注意一些特别的月份
Month(月) :可以用0-11
Day-of-Week(每周):可以用数字1-7表示(1 = 星期日)

特殊符号

  • * 标识任何值
  • , 用于多个日期的连接
  • - 用于多个范围的连接
  • / 用于标识每隔多少时间的操作

Example

  • 具体实现参考

https://github.com/kelektiv/node-cron/tree/master/examples

绕了个大圈,走了很多冤枉路才发现 ,原来做人,不是永远只有一条路。
其实做什么事情,根本不需要分得那么清楚,闭上眼睛,就分不出来黑与白了。

天行者
  • 安装protobufjs
npm i protobufjs -g

编写一个需要交互的proto文件

  • awesome.proto
// awesome.proto
syntax = "proto3";

message AwesomeMessage {
string name = 1;
}

编译一个静态的js文件

  • 编译静态js文件
  • 编译ts版本
pbjs -t static-module -w commonjs -o awesome.js awesome.proto
pbts -o awesome.d.ts awesome.js

awesome.js的引用需要修改

var $protobuf = window.protobuf || {};

导入一个protobuf.js的最小版本

  • 引入一个插件

protobuf.min.js

加入两个编译成的文件

简单测试

import { AwesomeMessage } from "./proto/awesome";
...
let asm = AwesomeMessage.fromObject({
name: '你好Proto',
});

const buf = AwesomeMessage.encode(asm).finish();
console.log(buf);

let message = AwesomeMessage.decode(buf);
let object = AwesomeMessage.toObject(message, {
longs: String,
enums: String,
bytes: String,
// see ConversionOptions
});
console.log(object);

写在前头

本实例主要给刚接触CocosCreator和网络开发小白使用。老司机可以马上调头,这是开往幼儿园的专列。

背景

聊天室作为大多数网络游戏开发人员的第一个项目,实现了一对多,一对一的数据交互,作为基石一般的存在,可以在上面搭建出各种复杂多变的网络程序,此篇作为我网络游戏开发的第一篇,希望与大家共勉。

服务器的选择

与CocosCretor搭配的全栈解决方案当然是Nodejs了

  • Pomelo
    • 网易开源的游戏应用服务器
    • 能用简单的代码搭建一个稳定的服务器
    • 丰富的组件
    • 完善的客户端类库
  • WebSocket
  • Socket.io
    • 建立在webSicket之上
    • 拥有完善的处理方法
    • 类库更新十分勤快 拥有大量的用户
选型 结果
Pomelo 比较适合有一定的网络开发基础的人使用。 PASS
WebSocket的开发相对比较简单,但是有更好的方案. PASS
Socket.io 反正我没找到更好的… Bingo

服务器的开发

码第一行代码之前默念 善哉善哉 bug去也

1.安装npm包
找到你的项目目录执行以下包安装命令

npm install express --save
npm install socket.io --save
npm install underscore --save

2.引入包
编写一个app.js的文件

const express = require('express');
const app = express();
const http = require('http').Server(app);
const sio = require('socket.io')(http);
const _ = require('underscore');

3.设置跨域访问
之后使用express做工具服务器的时候会用到

//设置跨域访问
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By",' 3.2.1')
res.header("Content-Type", "application/json;charset=utf-8");
next();
});

4.绑定端口

app.get('/',(req,res)=>{
res.send('<h1>Hello world</h1>');
});

http.listen(3000, ()=>{
console.log('listening on http://127.0.0.1:3000');
});

5.测试绑定

启动服务器

node app

打开网址查看 出现HelloWorld即为成功

http://127.0.0.1:3000

6.编写一个简单聊天服务器

  • 代码量50行左右 有完整的注释
  • 简单的分析一下
    • sio的on和emit与nodejs的事件监听和触发相似
    • connection用来监听客户端的链接
    • socket是获得的客户句柄
    • socket.on 用于注册自定义事件
    • user和msgObj的内容在客户端的Params.ts里
/**********************关于聊天的相关操作*************************/
//保存用户的数组
var userList = [];
//接收客户端的连接
sio.on('connection',socket=>{
//登录
socket.on('login',(user)=>{
console.log('login');
console.log(user);
user.id = socket.id;
userList.push(user);
//群发用户列表
sio.emit('userList',userList);
//发送当前用户列表信息
socket.emit('userInfo',user);
//除自己外广播用户登录信息
socket.broadcast.emit('loginInfo',user.name+"上线了。");
});
//客户端断开
socket.on('disconnect',()=>{
//查出当前离开的用户
let user = _.findWhere(userList,{id:socket.id});
if(user){
//剔除当前离线用户
userList = _.without(userList,user);
//发送当前用户列表信息
sio.emit('userList',userList);
//除自己外广播用户断线信息
socket.broadcast.emit('loginInfo',user.name+"下线了。");
}

});
//群发事件
socket.on('toAll',function(msgObj){
socket.broadcast.emit('toAll',msgObj);
});
//单发事件
socket.on('toOne',function(msgObj){
let toSocket = _.findWhere(sio.sockets.sockets,{id:msgObj.to});
toSocket.emit('toOne', msgObj);
});

/**
* 心跳包
*/
socket.on('game_ping',function(data){
socket.emit('game_pong');
});
});

聊天室基本界面

graph TD
H(loading界面)-->A
A(用户名输入界面)-->B(聊天室界面)
B-->D(群聊界面)
B-->E(私聊界面)

项目的实际界面截图

登录界面

聊天室的界面

发群聊消息

发私聊消息

简单起见 私聊消息红色显示

用户下线通知

用户上线通知

客户端的开发

客户端代码会在后面放出 简单的分析下几个类

NetUtil.ts 参考麒麟子的net.js

  • ts中window.io是不存在的需要使用转化获得
const io = (window as any).io || {};
  • 使用io.connect连接到服务器
init(){
let opts = {
'reconnection':false,
'force new connection': true,
'transports':['websocket', 'polling']
}
this.sio = io.connect('http://127.0.0.1:3000',opts);

this.sio.on('connect',(data)=>{
console.log('connect');
this.connected = true;
})

this.sio.on('disconnect',(data)=>{
console.log("disconnect");
this.connected = false;
});

this.startHearbeat();
}
  • 封装on / emit方法 方便使用
/**
* 绑定事件
* @param event
* @param cb
*/
on(event:string,cb){
this.sio.on(event,cb);
}

/**
* 击发服务器事件
* @param event
* @param data
*/
emit(event:string,data?:any){
if(data){
this.sio.emit(event,data);
return;
}
this.sio.emit(event);
}

LoadingCtrl.ts

  • 就干了一件事情初始化连接
  • 之后要优于其他操作的初始化都放到这里 比如 i18n
    //初始化项目
    initGame(){
    NetUtil.Instance.init();

    }

LoginCtrl.ts

  • 获得用户名 并发送给服务器
login(){
let name = this.userBox.string;
if(name.length<2){
return;
}
let user:User ={id:"",name,imgUrl:""};
NetUtil.Instance.emit('login',user);
}

ChatCtrl.ts

  • 注册服务器的事件
onLoad () {
//注册用户登入登出信息
NetUtil.Instance.on('loginInfo',(msg:string)=>{
cc.log(msg);
Toast.makeText(msg,Toast.LENGTH_LONG).show();
})
//获得当前用户信息
NetUtil.Instance.on('userInfo',(user:User)=>{
GameUtil.Instance.userInfo = user;
cc.log(user);
})
//广播的用户列表信息
NetUtil.Instance.on('userList',(userList)=>{
cc.find('Canvas/login_room').active = false;
//获取当前的用户列表
this.userList = userList;
//更新容器
this.updateUserList(this.userList);
});
//注册发送给全部人的消息
NetUtil.Instance.on('toAll',(msg:Message)=>{
let node = cc.instantiate(this.otherMsgItem);
node.getChildByName('name').getComponent(cc.Label).string = msg.from.name;
node.getChildByName('msgBox').getChildByName('msg').getComponent(cc.Label).string = msg.msg;
this.msgContent.addChild(node);
if(this.msgContent.height>480){
this.msgScrollView.scrollToBottom(0.3);
}
});
//注册发送给一个人的消息
NetUtil.Instance.on('toOne',(msg:Message)=>{
let node = cc.instantiate(this.otherMsgItem);
node.getChildByName('name').getComponent(cc.Label).string = msg.from.name;
node.getChildByName('msgBox').getChildByName('msg').getComponent(cc.Label).string = msg.msg;
node.getChildByName('msgBox').getChildByName('msg').color = cc.Color.RED;
this.msgContent.addChild(node);
if(this.msgContent.height>480){
this.msgScrollView.scrollToBottom(0.3);
}
});
}

UserNode.ts

  • 预制件通过user初始化
  • 注册了点击事件
  • 点击展示单独发送的面板
init(user:User){
this.user = user;
this.node.on(cc.Node.EventType.TOUCH_END,event=>{
//获得控制脚本
let chatCtrl = cc.find('Canvas/chat_room').getComponent(ChatCtrl);
chatCtrl.showSingleBox(this.user);
});
}

Params.ts

  • 定义了两个接口
export interface User{
id:string; //用户的id
name:string; //用户名
imgUrl:string; //用户头像的图片地址
}

export interface Message{
from:User ; //发送的用户
msg:string ; //发送的信息
to?:string ; //发送给的人 没有则发送全部
}

加入频道,实现分频道聊天

  • 频道的概念即为游戏中分房间的概念,游戏房间中的数据只对房间内的人广播,可以大大提高效率,减少消耗

之前用于保存用户的数组改为了对象

//保存用户的数组
var userList = {};

修改后的用户登录接口

  • userList[user.channel] 用来保存用户
  • join方法用于创建和加入频道
  • to方法用于切换到频道
  • 下面会出现的leave用于离开频道
//登录    
socket.on('login',(user)=>{
console.log('login');
console.log(user);
user.id = socket.id;
if(!userList[user.channel]){
userList[user.channel]=[];
}
userList[user.channel].push(user);
socket.join(user.channel);
//将频道赋值给socket
socket.channel = user.channel;
//群发用户列表
sio.to(user.channel).emit('userList',userList[user.channel]);
//发送当前用户列表信息
socket.emit('userInfo',user);
//除自己外广播用户登录信息
socket.broadcast.to(user.channel).emit('loginInfo',user.name+"上线了。");
});

客户端处修改

  • 加入频道输入框
  • 加入频道属性
export interface User{
id:string; //用户的id
name:string; //用户名
channel:string; //当前的频道
imgUrl:string; //用户头像的图片地址
}

加入数据库和用户校验

图例

注册一个用户

校验用户名 不能重复

上线提示

数据库内容查询

聊天数据

数据库相关

  • 使用sequelize(orm框架)操作数据库
  • 可以在不修改代码的情况下更换数据库
  • 当前使用sqlite3数据库 也可以切换到mysql

DbClient.js

  • 初始化数据库的实例
const Sequelize = require('sequelize');

const sequelize = new Sequelize('super', 'root', '123123', {
host: '127.0.0.1',
port: 3306,
//dialect: 'mysql',
dialect: 'sqlite',
operatorsAliases: false,
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
},
//sqlite只需要这个参数
storage:'./db/db.sqlite'
});

sequelize.authenticate().then(() => {
console.log('数据库连接成功');
}).catch(err => {
console.error('数据库连接失败', err);
});

module.exports = sequelize;

mondels/User.js

  • 用户的模型
const Sequelize = require('sequelize');
const dbClient = require('../DbClient');

//定义表结构
let User = dbClient.define('tb_users', {
uid:{type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true},
account:{type:Sequelize.STRING , allowNull:false},
password:{type:Sequelize.STRING , allowNull:false},
imgurl:{type:Sequelize.STRING , },
channel:{type:Sequelize.STRING , },
age:{type:Sequelize.INTEGER, defaultValue:0},
});

//没有表的时候创建表
User.sync();

module.exports = User;

mondels/Message.js

  • 信息的模型
const Sequelize = require('sequelize');
const dbClient = require('../DbClient');

//定义表结构
let Message = dbClient.define('tb_messages', {
uid:{type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true},
fromuid:{type: Sequelize.INTEGER , allowNull:true},
message:{type:Sequelize.STRING(1024) , allowNull:false},
touid:{type:Sequelize.STRING , defaultValue:""}
});

//没有表的时候创建表
Message.sync();

module.exports = Message;

服务器中添加一个注册的方法

  • sequelize的使用可以参考官网的文档
................
//注册
socket.on('register',registerObj=>{
User.findOrCreate({where: {account: registerObj.name}, defaults: {password:registerObj.password}})
.spread((user, created) => {
// console.log(user.get({
// plain: true
// }))
// console.log(created)
socket.uid = user.get('uid');
if(created){
//发送当前用户列表信息
socket.emit('registerInfo','注册成功');
}
else{
//发送当前用户列表信息
socket.emit('registerInfo','用户名已经存在');
}
})
});
..............

更新下载:

GitHub地址:https://github.com/SeaPlanet/cocoscreator_chat

Tips:

Socket.io的默认事件列表

服务端事件

事件名称 事件解释
connection socket连接成功之后触发,用于初始化
message 客户端通过socket.send来传送消息时触发此事件
anything 收到任何事件时触发
disconnect socket失去连接时触发

客户端事件

事件名称 事件解释
connect 连接成功
connecting 正在连接
disconnect 断开连接
connect_failed 连接失败
error 错误发生,并且无法被其他事件类型所处理
message 同服务器端message事件
anything 同服务器端anything事件
reconnect_failed 重连失败
reconnect 成功重连
reconnecting 正在重连

Promise链式调用

首先有多个异步方法

  • 返回一个Promise对象
  • 有50%的几率返回正确 50%返回错误
function p1() : Promise<string> {
return new Promise<string>((resolve, reject) => {
//延时操作 使用setTimeout模拟
setTimeout(()=>{
if(Math.random() > 0.5){
resolve('p1 success')
} else {
reject('p1 error')
}
}, 500);
})
}

function p2() : Promise<string> {
return new Promise<string>((resolve, reject) => {
//延时操作 使用setTimeout模拟
setTimeout(()=>{
if(Math.random() > 0.5){
resolve('p2 success')
} else {
reject('p2 error')
}
}, 500);
})
}

调用这个方法

  • 链式调用
function main() {
p1()
.then(res => {
console.log(res)
return p2()
})
.then(res => {
console.log(res)
})
.catch(err => {
console.log(err)
})
}

调用main方法

  • 调用和一般方法一样
main()

async & await

首先编写一个异步方法

  • 返回一个Promise对象
  • 有50%的几率返回正确 50%返回错误
function asyncResult() : Promise<string> {
return new Promise<string>((resolve, reject) => {
//延时操作 使用setTimeout模拟
setTimeout(()=>{
if(Math.random() > 0.5){
resolve('success')
} else {
reject('error')
}
}, 1000);
})
}

调用这个异步方法

  • 使用await 需要加async标识方法
  • 因为异步方法我们定义了reject所以要抓取异常
async function main() {
let ans = await asyncResult().catch(err => {
console.log(err)
})
if (ans) {
console.log('成功!', ans)
} else {
console.log('失败!')
}
}

调用main方法

  • 调用和一般方法一样
main()

"no-alert": 0,//禁止使用alert confirm prompt
"no-array-constructor": 2,//禁止使用数组构造器
"no-bitwise": 0,//禁止使用按位运算符
"no-caller": 1,//禁止使用arguments.caller或arguments.callee
"no-catch-shadow": 2,//禁止catch子句参数与外部作用域变量同名
"no-class-assign": 2,//禁止给类赋值
"no-cond-assign": 2,//禁止在条件表达式中使用赋值语句
"no-console": 2,//禁止使用console
"no-const-assign": 2,//禁止修改const声明的变量
"no-constant-condition": 2,//禁止在条件中使用常量表达式 if(true) if(1)
"no-continue": 0,//禁止使用continue
"no-control-regex": 2,//禁止在正则表达式中使用控制字符
"no-debugger": 2,//禁止使用debugger
"no-delete-var": 2,//不能对var声明的变量使用delete操作符
"no-div-regex": 1,//不能使用看起来像除法的正则表达式/=foo/
"no-dupe-keys": 2,//在创建对象字面量时不允许键重复 {a:1,a:1}
"no-dupe-args": 2,//函数参数不能重复
"no-duplicate-case": 2,//switch中的case标签不能重复
"no-else-return": 2,//如果if语句里面有return,后面不能跟else语句
"no-empty": 2,//块语句中的内容不能为空
"no-empty-character-class": 2,//正则表达式中的[]内容不能为空
"no-empty-label": 2,//禁止使用空label
"no-eq-null": 2,//禁止对null使用==或!=运算符
"no-eval": 1,//禁止使用eval
"no-ex-assign": 2,//禁止给catch语句中的异常参数赋值
"no-extend-native": 2,//禁止扩展native对象
"no-extra-bind": 2,//禁止不必要的函数绑定
"no-extra-boolean-cast": 2,//禁止不必要的bool转换
"no-extra-parens": 2,//禁止非必要的括号
"no-extra-semi": 2,//禁止多余的冒号
"no-fallthrough": 1,//禁止switch穿透
"no-floating-decimal": 2,//禁止省略浮点数中的0 .5 3.
"no-func-assign": 2,//禁止重复的函数声明
"no-implicit-coercion": 1,//禁止隐式转换
"no-implied-eval": 2,//禁止使用隐式eval
"no-inline-comments": 0,//禁止行内备注
"no-inner-declarations": [2, "functions"],//禁止在块语句中使用声明(变量或函数)
"no-invalid-regexp": 2,//禁止无效的正则表达式
"no-invalid-this": 2,//禁止无效的this,只能用在构造器,类,对象字面量
"no-irregular-whitespace": 2,//不能有不规则的空格
"no-iterator": 2,//禁止使用__iterator__ 属性
"no-label-var": 2,//label名不能与var声明的变量名相同
"no-labels": 2,//禁止标签声明
"no-lone-blocks": 2,//禁止不必要的嵌套块
"no-lonely-if": 2,//禁止else语句内只有if语句
"no-loop-func": 1,//禁止在循环中使用函数(如果没有引用外部变量不形成闭包就可以)
"no-mixed-requires": [0, false],//声明时不能混用声明类型
"no-mixed-spaces-and-tabs": [2, false],//禁止混用tab和空格
"linebreak-style": [0, "windows"],//换行风格
"no-multi-spaces": 1,//不能用多余的空格
"no-multi-str": 2,//字符串不能用\换行
"no-multiple-empty-lines": [1, {"max": 2}],//空行最多不能超过2行
"no-native-reassign": 2,//不能重写native对象
"no-negated-in-lhs": 2,//in 操作符的左边不能有!
"no-nested-ternary": 0,//禁止使用嵌套的三目运算
"no-new": 1,//禁止在使用new构造一个实例后不赋值
"no-new-func": 1,//禁止使用new Function
"no-new-object": 2,//禁止使用new Object()
"no-new-require": 2,//禁止使用new require
"no-new-wrappers": 2,//禁止使用new创建包装实例,new String new Boolean new Number
"no-obj-calls": 2,//不能调用内置的全局对象,比如Math() JSON()
"no-octal": 2,//禁止使用八进制数字
"no-octal-escape": 2,//禁止使用八进制转义序列
"no-param-reassign": 2,//禁止给参数重新赋值
"no-path-concat": 0,//node中不能使用__dirname或__filename做路径拼接
"no-plusplus": 0,//禁止使用++,--
"no-process-env": 0,//禁止使用process.env
"no-process-exit": 0,//禁止使用process.exit()
"no-proto": 2,//禁止使用__proto__属性
"no-redeclare": 2,//禁止重复声明变量
"no-regex-spaces": 2,//禁止在正则表达式字面量中使用多个空格 /foo bar/
"no-restricted-modules": 0,//如果禁用了指定模块,使用就会报错
"no-return-assign": 1,//return 语句中不能有赋值表达式
"no-script-url": 0,//禁止使用javascript:void(0)
"no-self-compare": 2,//不能比较自身
"no-sequences": 0,//禁止使用逗号运算符
"no-shadow": 2,//外部作用域中的变量不能与它所包含的作用域中的变量或参数同名
"no-shadow-restricted-names": 2,//严格模式中规定的限制标识符不能作为声明时的变量名使用
"no-spaced-func": 2,//函数调用时 函数名与()之间不能有空格
"no-sparse-arrays": 2,//禁止稀疏数组, [1,,2]
"no-sync": 0,//nodejs 禁止同步方法
"no-ternary": 0,//禁止使用三目运算符
"no-trailing-spaces": 1,//一行结束后面不要有空格
"no-this-before-super": 0,//在调用super()之前不能使用this或super
"no-throw-literal": 2,//禁止抛出字面量错误 throw "error";
"no-undef": 1,//不能有未定义的变量
"no-undef-init": 2,//变量初始化时不能直接给它赋值为undefined
"no-undefined": 2,//不能使用undefined
"no-unexpected-multiline": 2,//避免多行表达式
"no-underscore-dangle": 1,//标识符不能以_开头或结尾
"no-unneeded-ternary": 2,//禁止不必要的嵌套 var isYes = answer === 1 ? true : false;
"no-unreachable": 2,//不能有无法执行的代码
"no-unused-expressions": 2,//禁止无用的表达式
"no-unused-vars": [2, {"vars": "all", "args": "after-used"}],//不能有声明后未被使用的变量或参数
"no-use-before-define": 2,//未定义前不能使用
"no-useless-call": 2,//禁止不必要的call和apply
"no-void": 2,//禁用void操作符
"no-var": 0,//禁用var,用let和const代替
"no-warning-comments": [1, { "terms": ["todo", "fixme", "xxx"], "location": "start" }],//不能有警告备注
"no-with": 2,//禁用with
"array-bracket-spacing": [2, "never"],//是否允许非空数组里面有多余的空格
"arrow-parens": 0,//箭头函数用小括号括起来
"arrow-spacing": 0,//=>的前/后括号
"accessor-pairs": 0,//在对象中使用getter/setter
"block-scoped-var": 0,//块语句中使用var
"brace-style": [1, "1tbs"],//大括号风格
"callback-return": 1,//避免多次调用回调什么的
"camelcase": 2,//强制驼峰法命名
"comma-dangle": [2, "never"],//对象字面量项尾不能有逗号
"comma-spacing": 0,//逗号前后的空格
"comma-style": [2, "last"],//逗号风格,换行时在行首还是行尾
"complexity": [0, 11],//循环复杂度
"computed-property-spacing": [0, "never"],//是否允许计算后的键名什么的
"consistent-return": 0,//return 后面是否允许省略
"consistent-this": [2, "that"],//this别名
"constructor-super": 0,//非派生类不能调用super,派生类必须调用super
"curly": [2, "all"],//必须使用 if(){} 中的{}
"default-case": 2,//switch语句最后必须有default
"dot-location": 0,//对象访问符的位置,换行的时候在行首还是行尾
"dot-notation": [0, { "allowKeywords": true }],//避免不必要的方括号
"eol-last": 0,//文件以单一的换行符结束
"eqeqeq": 2,//必须使用全等
"func-names": 0,//函数表达式必须有名字
"func-style": [0, "declaration"],//函数风格,规定只能使用函数声明/函数表达式
"generator-star-spacing": 0,//生成器函数*的前后空格
"guard-for-in": 0,//for in循环要用if语句过滤
"handle-callback-err": 0,//nodejs 处理错误
"id-length": 0,//变量名长度
"indent": [2, 4],//缩进风格
"init-declarations": 0,//声明时必须赋初值
"key-spacing": [0, { "beforeColon": false, "afterColon": true }],//对象字面量中冒号的前后空格
"lines-around-comment": 0,//行前/行后备注
"max-depth": [0, 4],//嵌套块深度
"max-len": [0, 80, 4],//字符串最大长度
"max-nested-callbacks": [0, 2],//回调嵌套深度
"max-params": [0, 3],//函数最多只能有3个参数
"max-statements": [0, 10],//函数内最多有几个声明
"new-cap": 2,//函数名首行大写必须使用new方式调用,首行小写必须用不带new方式调用
"new-parens": 2,//new时必须加小括号
"newline-after-var": 2,//变量声明后是否需要空一行
"object-curly-spacing": [0, "never"],//大括号内是否允许不必要的空格
"object-shorthand": 0,//强制对象字面量缩写语法
"one-var": 1,//连续声明
"operator-assignment": [0, "always"],//赋值运算符 += -=什么的
"operator-linebreak": [2, "after"],//换行时运算符在行尾还是行首
"padded-blocks": 0,//块语句内行首行尾是否要空行
"prefer-const": 0,//首选const
"prefer-spread": 0,//首选展开运算
"prefer-reflect": 0,//首选Reflect的方法
"quotes": [1, "single"],//引号类型 `` "" ''
"quote-props":[2, "always"],//对象字面量中的属性名是否强制双引号
"radix": 2,//parseInt必须指定第二个参数
"id-match": 0,//命名检测
"require-yield": 0,//生成器函数必须有yield
"semi": [2, "always"],//语句强制分号结尾
"semi-spacing": [0, {"before": false, "after": true}],//分号前后空格
"sort-vars": 0,//变量声明时排序
"space-after-keywords": [0, "always"],//关键字后面是否要空一格
"space-before-blocks": [0, "always"],//不以新行开始的块{前面要不要有空格
"space-before-function-paren": [0, "always"],//函数定义时括号前面要不要有空格
"space-in-parens": [0, "never"],//小括号里面要不要有空格
"space-infix-ops": 0,//中缀操作符周围要不要有空格
"space-return-throw-case": 2,//return throw case后面要不要加空格
"space-unary-ops": [0, { "words": true, "nonwords": false }],//一元运算符的前/后要不要加空格
"spaced-comment": 0,//注释风格要不要有空格什么的
"strict": 2,//使用严格模式
"use-isnan": 2,//禁止比较时使用NaN,只能用isNaN()
"valid-jsdoc": 0,//jsdoc规则
"valid-typeof": 2,//必须使用合法的typeof的值
"vars-on-top": 2,//var必须放在作用域顶部
"wrap-iife": [2, "inside"],//立即执行函数表达式的小括号风格
"wrap-regex": 0,//正则表达式字面量用小括号包起来
"yoda": [2, "never"]//禁止尤达条件