node
node 特点
node 单线程
进程是操作系统分配资源和调度任务的基本单位,线程是建立在进程上的一次程序运行单位,一个进程上可以有多个线程。
node 高并发
核心:事件循环机制
node 事件循环与浏览器的差异
浏览器:宏任务1 -> 宏任务1中的微任务 -> 宏任务2 -> 宏任务2中的微任务... node: 宏任务1 -> 宏任务2 -> 宏任务1中的微任务 -> 宏任务2中的微任务...
此差异只在 node10 及以下存在,11以上与浏览器一致
setTimeout(() => {
console.log('timer1');
Promise.resolve().then(function() {
console.log('promise1');
})
}, 0);
setTimeout(() => {
console.log('timer2');
Promise.resolve().then(function() {
console.log('promise2');
})
}, 0);
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
输出:
浏览器: timer1 -> promise1 -> timer2 -> promise2 node: timer1 -> timer2 -> promise1 -> promise2
koa 洋葱模型
const Koa = require('koa');
const app = new Koa();
app.use(async (ctx, next) => {
ctx.body = 'Hello World';
console.log('first before next')
next()
console.log('first after next')
});
app.use(async (ctx, next) => {
console.log('sencond before next')
next()
console.log('sencond after next')
ctx.body = 'use next';
});
app.listen(3500, () => {
console.log('run on port 3500')
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
结果:
first before next
sencond before next
sencond after next
first after next
1
2
3
4
2
3
4
从第一个中间件开始,最后从第一个中间件结束,就像针穿过洋葱一样,从最外层进去,然后从最外层出来一样。
npm install 的执行过程
- 发出npm install命令
- 查询 node_modules 目录之中是否已经存在指定模块
- 若存在,不再重新安装
- 若不存在
- npm 向 registry 查询模块压缩包的网址
- 下载压缩包,存放在根目录下的.npm目录里
- 解压压缩包到当前项目的 node_modules 目录
RPC
RPC(Remote Procedure Call)中文名「远程过程调用」,又是一个很蹩脚的翻译。我们拆开理解下,「过程」也叫方法或函数,「远程」就是说方法不在当前进程里,而是在其他进程或机器上面,合起来 RPC 就是调用其他进程或机器上面的函数。 1
两个node程序之间怎样交互?
用 fork ,原理是子程序用 process.on 、rocess.send ,父程序里用 child.on ,child.send进行交互. 代码演示
1) fork-parent.js
var cp = require('child_process');
var child = cp.fork('./fork-child.js');
child.on('message', function(msg){
console.log('老爸从儿子接受到数据:', msg);
});
child.send('我是你爸爸,送关怀来了!');
2) fork-child.js
process.on('message', function(msg){
console.log("儿子从老爸接收到的数据:", msg);
process.send("我不要关怀,我要银民币!");
});
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
怎样让一个js文件变得像 linux 命令一样可执行?
- 在 myCommand.js 文件头部加入 #!/usr/bin/env node
- chmod 命令把 js 文件改为可执行即可
- 进入文件目录,命令行输入 myComand 就是相当于 node myComand.js 了
AMD, CMD, CommonJS 、 es6 module 区别
- ADM: 依赖前置,提前执行。也就是说,在define方法里传入的依赖模块(数组),会在一开始就下载并执行。
- CMD: 推崇依赖就近,延迟执行。也就是说,只有到require时依赖模块才执行。
- CommonJS:
- 所有代码都运行在模块作用域,不会污染全局作用域;
- 模块是同步加载的,即只有加载完成,才能执行后面的操作;
- 模块在首次执行后就会缓存,再次加载只返回缓存结果,如果想要再次执行,可清除缓存;
- CommonJS输出是值的拷贝(即,require返回的值是被输出的值的拷贝,模块内部的变化也不会影响这个值)。
- es6 module:
- CommonJS模块是运行时加载,ES6 Module是编译时输出接口;
- CommonJS加载的是整个模块,将所有的接口全部加载进来,ES6 Module可以单独加载其中的某个接口;
- CommonJS输出是值的拷贝,ES6 Module输出的是值的引用,被输出模块的内部的改变会影响引用的改变;
- CommonJS this指向当前模块,ES6 Module this指向undefined; 1
UMD
(function(root, factory) {
if (typeof module === 'object' && typeof module.exports === 'object') {
console.log('是commonjs模块规范,nodejs环境');
module.exports = factory();
} else if (typeof define === 'function' && define.amd) {
console.log('是AMD模块规范,如require.js');
define(factory());
} else if (typeof define === 'function' && define.cmd) {
console.log('是CMD模块规范,如sea.js');
define(function(require, exports, module) {
module.exports = factory();
});
} else {
console.log('没有模块环境,直接挂载在全局对象上');
root.umdModule = factory();
}
}(this, function() {
return {
name: '我是一个umd模块'
};
}));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
commonjs 、 es6 的模块循环引用
CommonJS 和 es6 的处理方式不同
- CommonJS
- 互相require: CommonJS的做法是,一旦出现某个模块被"循环加载",就只输出已经执行的部分,还未执行的部分不会输出。
- es6
- ES6根本不会关心是否发生了"循环加载",只是生成一个指向被加载模块的引用,需要开发者自己保证,真正取值的时候能够取到值。 1
← webpack 进阶 es6 →