C++老司机的Node.js学习记录

对于写惯C++这种强类型语言的人来说,js代码简直天马行空任性的要死啊有木有,很多写法完全无厘头啊有木有。还好有Typescript来让我缓一缓。
安装配置
- 安装Node.js, 改成国内镜像:
npm install -g cnpm --registry=https://registry.npm.taobao.org
- 安装Typescript
cnpm install -g typescript
- 安装Visual Studio Code,安装下面的扩展
- Node.js Modules Intellisense
- TSLint
- 建立一个文件夹当工程根目录
- 用VS Code打开,在终端里输入下面的命令:
npm init
建立package.json文件cnpm install --save @types/node
Node.js的类型库tsc --init
建立tsconfig.json文件cnpm install --save tslint
在工程里装个tslint- 修改
tsconfig.json
, 把"outDir": "./js/", "sourceMap": true,
这两条反注释,outDir写输出的js路径。这样才能在VS Code里调试。
- 按快捷键Ctrl+Shift+B,建立一个launch.json,添加一个配置,如下设置:
1
2
3
4
5
6
7
8
9{
"type": "node",
"request": "launch",
"name": "Launch TS",
"program": "${file}",
"outFiles": [
"${workspaceFolder}/**/*.js"
]
}, - 再次按Ctrl+Shift+B,选择tsc watch那条,这样写ts文件就会自动编译成js了。
- 对照菜鸟教程学起来http://www.runoob.com/nodejs/nodejs-tutorial.html
事件驱动
1 | import {EventEmitter} from 'events'; |
输出:
1 | hello world |
on注册事件,emit触发。
Node.js几乎所有类型都实现了EventEmitter,javascript是单线程异步操作的,工作原理是在程序内把事件处理函数都挂好,异步操作走起。最后进入一个消息循环,完成啦出错啦啥的来了就触发事件。
缓冲区
缓冲区Buffer有点像内存块,支持复制、比较、裁剪。
1 | let buf = Buffer.alloc(10); |
流
Node.js里几乎所有的IO操作都抽象成了流操作。
流分四种,可读Readable、可写Writable、双向Duplex、转换Transform
读操作
1 | import * as fs from 'fs'; |
常用的事件有data, end, error, finish。error比较特殊,如果不处理会当作异常抛出。
写操作
1 | import * as fs from 'fs'; |
输出:
1 | Done! |
注意看程序输出的先后顺序
管道
1 | import * as fs from 'fs'; |
输出:
1 | Done! |
管道原理,以及流控制,从http://taobaofed.org/blog/2017/08/31/nodejs-stream/抄来的一个模拟pipe的代码可以看出一二:
1 | Readable.prototype.pipe = function(writable, options) { |
上面做了五件事情:
- emit(pipe),通知写入
- .write(),新数据过来,写入
- .pause(),消费者消费速度慢,暂停写入
- .resume(),消费者完成消费,继续写入
- return writable,支持链式调用
模块
Typescript的模块系统和ES6的差不多,直接export就可以了
1 | //mod.ts的代码 |
1 | //调用mod.ts |
小坑
this
Javascript的this和C++的不一样,它是在调用的时候才确定的。比如下面抄来的代码:
1 | var name = "windowsName"; |
setTimeout里的函数在100ms后调用,那时候调用它的是全局值,所以这时this就是全局值。解决办法是用bind。
类?对象?函数?
Javascript除了基本类型,其它什么都是对象。包括类型(class)、函数什么的也是对象。这就容易搞晕,用Typescript还好一些。
我是这么理解的,不知道对不对:
- 给类(class)加属性、方法类似于C++里的静态属性、方法。
- 类(class)有个prototype属性,在prototype上添加的属性方法可以被类实例调用。
- 实例有个__proto__属性,指向了所属类的prototype。