Node学习
JavaScript是一门“完整”的语言: 它可以使用在不同的上下文中。Node.js事实上就是另外一种上下文,它允许在后端(脱离浏览器环境)运行JavaScript代码。
要实现在后台运行JavaScript代码,代码需要先被解释然后正确的执行。Node.js的原理正是如此,它使用了Google的V8虚拟机 (Google的Chrome浏览器使用的JavaScript执行环境),来解释和执行JavaScript代码。
因此,Node.js事实上既是一个运行时环境,同时又是一个库。
在面向对象的语言中,当我们谈到对象,指的是类或者结构体的实例。对象根据他们实例化的模板(就是所谓的类),会拥有不同的 属性和方法。但在JavaScript里对象不是这个概念。在JavaScript中,对象就是一个键/值对的集合 -- 你可以把JavaScript的对象想象成一个键为字符串类型的字典。
使用node开发http服务器一些感觉
一个http服务,他应该拥有的模块:
- router模块专注于路由以及选择的对应的事件,类似于spring中的dispatcherservlet,负责接受和分发请求到对应的执行模块中。
- 对应的server服务端模块,用于启动一个基础的HTTP服务器
- 真正请求处理的模块,用于处理真正的请求(此处一般会更加细分为mvc)
- 一个用于整合router与server的模块
个人理解这样的模块划分使各个模块的职责更加单一,降低各个模块的耦合度。
对比java socket
使用node,监听某个端口,当请求到来时就会去处理,单线程运行。
对比java socket监听端口的传统bio模式有些不同,每来一个新的连接都需要一个线程去监听,是否有请求发送进来,这样会导致连接一多线程多,且大部分为阻塞状态消耗系统资源。现在通常都会使用nio非阻塞的模式,使用一个线程去轮询所有连接了的tcp,其中有请求的就去处理。
js的单线程与nio模式很像。js属于单线程运行,它是一种单线程语言,所有任务都在一个线程上完成。为了解决io于网络开销,其拥有Event Loop(虽然能够减少io与网络等待开销,但其仍是单线程,并发能力如何?面对运算密集型的会不会是短板)。
Event Loop
"Event Loop是一个程序结构,用于等待和发送消息和事件。(a programming construct that waits for and dispatches events or messages in a program.)"
在程序中设置两个线程:一个负责程序本身的运行,称为"主线程";另一个负责主线程与其他进程(主要是各种I/O操作)的通信,被称为"Event Loop线程"(可以译为"消息线程")。
上图主线程的绿色部分,还是表示运行时间,而橙色部分表示空闲时间。每当遇到I/O的时候,主线程就让Event Loop线程去通知相应的I/O程序,然后接着往后运行,所以不存在红色的等待时间。等到I/O程序完成操作,Event Loop线程再把结果返回主线程。主线程就调用事先设定的回调函数,完成整个任务。
node的模型
node.js接受到的请求都会加入到EventQueue中,会等到EventLoop来进行处理,对于EventLoop中有阻塞操作的则会将其加入ThreadPool中等待其准备就绪再加入EventQueue中。
多进程
node虽然为单线程,但由于其模型结构所以对cpu的利用率还是超高的。但对于现在多核的cpu,单线程是发回不了其真正运算能力。在多核 CPU 系统之上,可以通过 child_process.fork
开启多个进程,即多个进程来发挥多核。
例如,如下代码会根据cpu的核数,来创建多少个进程。于是就会有多少个线程来真正的执行处理
const cluster = require('cluster');
const os = require('os');
if (cluster.isMaster) {
const cpus = os.cpus().length;
console.log('forking for ', cpus, ' CPUS');
for(let i = 0;i<cpus;i++) {
cluster.fork();
}
} else {
require('./index.js');
}
npm install 安装相应的依赖
进入到app.js 的目录运行 node app.js 即可启动
export
node中引入其他js代码中的方法 需要在原js代码中export,调用者进行require。
node中引入其他模块使用的是必包,如下所示,于是引用模块中的全局变量s现在变成了匿名函数内部的局部变量。如果Node.js继续加载其他模块,这些模块中定义的“全局”变量s也互不干扰。
(function () {
// 读取的hello.js代码:
var s = 'Hello';
var name = 'world';
console.log(s + ' ' + name + '!');
// hello.js代码结束
})();
export原理
require("./xxx")一个文件时,实际上会把此文件的export加入到module的exports变量中,并将exports返回给调用者。于是var xxx = require("./xxx")就能够在xxx变量中获取到其exports的全部变量。
node新建项目
- 创建一个新的文件夹
- npm init,初始化一个简单的package.json文件,执行该命令后终端会依次询问 name, version, description 等字段。**npm init --yes|-y :**作用同上,偷懒不用一直按enter
- touch index.js,