最近负责做一个采集传感器数据并以API下发控制命令的后台,前期用Python做了一个原型,通过调用云平台API获取数据然后API下发控制命令给云平台再转发给设备。考虑到设备数量(虽然这点数量根本谈不上并发)和控制精度,后来决定采用Node.js做一个接收云平台数据推送和API下发控制的后台(其实Python也能做,大不了用我熟悉的Flask,不过考虑到想学点新东西嘿嘿),那么自然而然也就选择了提到Node就会想到的Express框架。虽然之前在前端上用过js,但是用来写后台还是第一次,所以头几天由于不熟悉异步编程的思维导致重写了好几个模块和函数。一个月过去了这个项目基本也写、测完了,现在来回顾一下遇到的萝卜和坑,给自己以后提个醒。

 


       

1.一开始用Python做第一个方案即原型的时候,没有理清整个控制流程和需求,所以很多函数改了又改。虽然项目一开始的时候,很多需求都没有也不会确定下来,所以这时候做的就是要把项目大致拆分,仔细想想各个可能性,然后对每个部分写对应的模块,尽量做兼容性设计,到后面很方便,特别是越往后甚至会有“还好这个功能、这个函数接口我当时灵机一动这么设计的”的感觉。

 


       

2.要有“整体”思维,不能像以前做C的小项目一样,总是想到什么写什么或者写到哪里再想继续写哪里,这样带来的后果就是控制的东西越多、业务越复杂,想不到的情况就更多。好比控制空调的流程,不管中间过程怎么样、用户有什么样的奇怪操作,能打开空调的参数就2个:一个是温度过高或过低,一个就是房间里有人。而怎么调用空调控制函数就另写控制逻辑函数,也就是说要保证各个模块的相对独立性。

 


       

3.写Python时,一开始就遵守PEP8来写,主要是命名规范上。例如包和模块名、函数名和变量名全用小写和下划线,类名首字母大写等等。此举是为了规范编程(其实一开始是因为用Pycharm给了一大堆PEP8警告看着很不爽)。

 


       

4.然后就是Node.js上遇到的萝卜和坑了。

  1. 导出多个模块:
    module.exports = {
        app,
        logger
    };
    或者用属性赋值的方法。
  2. 善用Promise还有箭头函数,特别是前者,把经常调用的模块和有io的写成Promise来调用,特别是用来调用api和读写数据库的函数,方便管理和阅读。但是这里也发现JS一个“缺点”,就是当回调层次多了之后都是thenthenthen。
  3. http模块中,一定不能只
    res.on('data', (chunk) => {
        resolve(chunk);
    });
    因为这里是一开始在教程找的,忘记到官方文档校对了,一开始没出问题,但是当我调用了一个数据量比较大的api时出现了问题,总是显示JSON的parse失败,后来看了文档才发现那个教程不严谨,没有监听end事件导致收到的结果数据不全,所以正确的是这样:
    let getRequestReq = http.request(options, function (res) {
        let chunk = '';
        res.setEncoding('utf8');
        res.on('data', (chunk_temp) => {
            chunk += chunk_temp;
        });
        res.on('end', () => {
            try {
                chunk = JSON.parse(chunk);
            }
            catch (e) {
            }
            if (chunk['error'] === "succ") {
                resolve(chunk);
            }
            else {
                reject(chunk);
            }
        });
    });
    getRequestReq.on('error', (e) => {
        reject(e);
    });
    getRequestReq.end();

     

  4. 第一次用Node.js的同时也是第一次用pug模板语法,之前习惯了jinja2真的不熟悉这么写HTML。不过这次不需要怎么写前端页面,也就写了十几行,所以就记两条吧。一是当想在页面写js的时候(虽然应该把js写成文件):
    script(type='text/javascript').
            $(function () {
    });
    二是在标签中嵌套标签和文字时,应该用'|'号:
    label#arg I am
                code THE
                |man
    //相当于:
    <label id="arg">I am<code>THE</code>man</label>

     

  5. 这条其实在写Flask就用过,只是又忘了是啥了。js的源映射,当然了这里只是把代码压缩中的用途写在html页面上的js函数的最后来方便调试的。
    //@ sourceURL=my_form.js

     

  6. 在pug中引用静态文件时,以及在js文件发送ajax请求时,如果在开头带上了'/',那么在使用1级域名,也就是通过xxx.xx.xxx.xx:port/来访问时是没有问题的,但是当用xxx.xx.xxx.xx:port/abc/来访问就会导致url错误,所以不应该加上'/',也就是说用相对路径。

 


 

5.这个项目说难度也没什么难度,因为业务不复杂。 主要还是熟悉异步编程思维,和熟悉项目的流程,特别是在对待需求方和我方关系的判断和事情处理上,远比写代码带来的经验重要得多。