Node 模块原理与用法详解
- 作者: 此用户为VIP用户
- 来源: 51数据库
- 2021-07-28
本文实例讲述了node 模块原理与用法。分享给大家供大家参考,具体如下:
简介
v8引擎本身就是用于chrome浏览器的js解释部分,但是ryan dahl,把v8搬到服务器,用于做服务器的软件。
node是一个专注于实现高性能web服务器优化的专家,在遇到v8而诞生的项目
- 没有历史包袱,没有同步i/o。不会出现一个同步i/o导致事件循环性能急剧降低的情况。
- v8性能足够好,远远比python,ruby等其它脚本语言的引擎快。
- javascript语言的闭包特性非常方便,比c中的回调函数好用。
node可以让javascript运行在服务器端的平台开发,它让javascript的触角延伸到了服务器端,可以与php,jsp,python,ruby等语言实现后端开发。
但node似乎有点不同:
- node不是一种独立的语言,与php,jsp,python,perl,ruby的“即使语言,也是平台”不同,node使用的是javascript进行编程,运行在javascript引擎上(v8)
- 与php,jsp等相比(php,jsp,.net都需要运行在服务器程序上,apache,naginx,tomcat,iis),node跳过了apcahe,naginx,iis等http服务器,它自己不用建设在任何服务器任何之上。node的设计理念与经典架构(lamp = linux + apache + mysql + php) 有着很大的不同,可以提供强大的伸缩能力。
- node没有web容器。
- node是花最小的硬件成本,追求更高的并发,更高的处理性能。
node特点
所谓特点,就是node如果解决服务器高性能瓶颈问题。
javascript有什么特点的时候,会立即想到 单线程,事件驱动, 面向对象。但是javascript精髓 觉得是 this, 闭包 ,作用域链, 函数。才使得这门语言魅力无穷。
单线程
在java,php,或者.net 等服务器端语言中,会为每一个用户端连接创建一个新的线程。而每个线程需要耗费大约2mb内存。理论上,一个8gb内存的服务器可以同时连接的最大用户数4000个左右。要让web应用程序支持更多的用户,就需要增加服务器的数量,而web应用程序的硬件成本就上升了。
node不为每个用户连接创建一个新的线程,而仅仅使用一个线程。当有用户连接了,就触发一个内部事件,并通过非阻塞i/o,事件驱动机制,让node程序宏观上也是并行的。node中,一个8gb内存的服务器,可以同时处理超过4万用户的连接。
单线程好处:操作系统完全不再有线程创建,销毁的时间开销。
单线程坏处:就是一个用户造成了线程的奔溃,整个服务都奔溃了,其它人的服务也就奔溃了。


单线程也能够造成宏观上的“并发”。
非阻塞i/o
非阻塞i/o non-blocking i/o
例子:访问数据库取得数据的时候,需要一段时间。
在传统的单线程处理机制中,在执行了访问数据库代码之后,整个线程都将暂停下来,等待数据库返回结果,才能执行后面的代码。也就是说i/o阻塞了代码的执行,极大降低了程序执行的效率。
node采用了非阻塞型i/o机制,因此在执行了访问数据库的代码之后,将立即转而执行后面的代码,把数据库返回的结果的处理代码放在回调函数中,从而提高了程序的执行效率。
当某个i/o执行完毕时,将以时间的形式通知执行i/o操作的线程,线程执行了这个事件的回调函数。为了处理异步i/o,线程必须有事件循环,不断的检查是否有未处理的时间。依次予以处理。
阻塞模式下,一个线程只能处理一项任务,要想提高吞吐量必须通过多线程。而非阻塞模式下,一个线程永远在执行计算操作,这个线程的cpu核心利用率永远是100%。 有一种类似 : 与其多人工作,但是好多人闲着,倒不如一个人工作,往死里干活。

事件驱动
事件驱动 event-driven
在node中,客户端请求建立连接,提交数据等行为,会触发相应的时间。在node中,在一个ie时时刻,只能执行一个事件回调函数,但是在执行一个事件回调函数的中途,可以转而处理其它事件(比如:有新用户连接),然后返回继续执行原事件的回调函数。这种处理机制,称为:"事件环"机制。
node底层是c++(v8也是c++) 编写。底层代码中,近半数都用户事件队列,回调函数队列的构建。用事件驱动来完成服务器的任务调度。用一个线程,担负起了处理非常多的任务。

单线程,减少内存开销,操作系统的内存换页。
如某一个任务,执行了,但是被i/o阻塞了,所以这个县城就阻塞了。非阻塞i/o,不会傻等i/o语句结束,而会执行后面的语句。利用事件驱动,不管是新用户的请求,还是老用户的i/o完成,都将以事件方式加入事件环中,等待调度。
node所有的i/o都是异步的,回调函数嵌套回调函数。
node是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高。
node的每个api都是异步的,并作为一个独立线程运行,使用异步函数调用,并处理并发。
node基本上所有的事件机制都是用设计模式中的观察者模式实现的。
node单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数。
模块
moduel
node中,以模块为单位划分所有功能,并且提供一个完整的模块加载机制,可以将应用程序话费为各个不同的部分。
node中,一个javascript文件中定义的变量,函数,都只在这个文件内部有效果。
侠义的说,每一个javascript文件都是一个模块,而多个javascript文件之间可以相互require,共同实现一个功能,整体外对,又称之为广义上的模块
好处:
- 减少重复代码量,增加可读性。
- 方便进行代码规划。
- 方面使用第三方模块。
当需要从js文件外部引用到这些变量,函数时,必须使用exprots对象,或者module.exprots进行暴露。使用者需要使用require(); 函数引入这个js文件。
function people( name,sex,age ){
this.name = name;
this.sex = sex;
this.age = age;
}
people.prototype = {
sayhello: function(){
console.log(this.name+this.sex+this.age);
}
};
// 暴露
module.exports = people;
// 使用
var people = require('./people.js');
var p1 = new people('zf','nv','23');
p1.sayhello();
一个javascript文件,可以向外exprots无数个变量,函数,对象,但是require(); 的时候,仅仅需要 载入一次js文件即可。 所以,无形之后,会增加一个顶层命名空间。
// 变量
// 需要变量引用 使用
exports.a = 10;
// 直接需要变量值使用.
module.exports = name;
// 对象
module.exports = {
name1: 123,
name2: 456
}
// 暴露结果: { name1: 123, name2: 456 }
exports.msg = {
name1: 1,
name2: 2
}
// 暴露结果 : { msg: { name1: 1, name2: 2 } }
// 函数
exports.showmsg = function () {
}
// 暴露结果 : { showmsg: [function] }
// 在 引用结果 需要 通过 变量 引用对象 执行
// var msg = require();
// msg.showmsg();
module.exports = function () {
}
// 暴露结果 [function]
// 引入文件的 变量 直接执行
模板引擎
数据绑定,成为一个完整的html字符串。
node中使用的模板:ejs 和 jade
后台模板引擎:
<ul>
<% for(var i = 0 ; i < news.length ; i++){ %>
<li><%= news[i] %></li>
<% } %>
</ul>
// 模板中需要的数据
var dictionary = {
a:6,
news : ["xixi","haha"]
};
http模块
主要类
class: http.server
var server = http.createserver();
server就是http.server类的实例。
常用的方法有:
server.listen(port, [hostname], [backlog], [callback])
class: http.serverresponse
var server = http.createserver(function(req,res){ });
res就是 http.serverresponse类的实例。
class: http.incomingmessage
``
var server = http.createserver(function(req,res){ });
``
req就是http.incomingmessage类的实例。
server对象
可以使用on语法监听某个事件。
var http = require('http');
var server = http.createserver();
server.on('request',function ( req,res ) {
res.setheader('content-type','text/html;charset=utf-8');
if ( req.url == '/' ){
res.end('index');
} else {
res.end('404');
}
});
server.listen(8080,'localhost');
req对象
每次上行请求头对象
req.headers //http上行请求头

req.httpversion // http请求的版本。现在基本上都是1.1 req.method // “get”、”post”就是请求的类型 req.url // 用户请求的网址
res对象
每次下行响应对象
res.end() // 每次都要有这个语句,表示这次的发送已经结束
// 参数必须是string、buffer(图片、文件)。
res.write() // 就是写http下行请求的body
res.setheader() // 设置返回的报文头部
res.statuscode = 404; // 设置状态码
res.writehead() // 和res.setheader差不多
res.writehead(288 , {"content-type":"text/plain"});
url模块
作用内置模块,解析url,解析地址。 分析和解析 url 的工具
url.parse()
url.parse()就是用来解析网址,接收一个字符串,返回一个json:
var obj = url.parse("http://localhost:8080/a/b/c/1.html?name=ting&age=21");

url.parse方法第二个参数如果是true,那么返回的对象中的query就是json
query: { xingming: 'xiaoming', age: '12' }
querystring模块
querystring模块是专门用来解析get请求的查询字符串的。
console.log( qs.parse('name=ting&age=21&hobby=run&hobby=sing') );
// 返回:{ name: 'ting', age: '21', hobby: [ 'run', 'sing' ] }
path模块
处理和转换文件路径的工具集,专门处理路径
path.basename() 返回路径中的文件名
path.dirname() 返回路径中的文件夹名
path.extname() 返回路径的拓展名
console.log( path.basename('/xixi/haha/a.html') ); //a.html
console.log( path.extname('/xixi/haha/a.html') ); //.html
console.log( path.dirname('/xixi/haha/a.html') ); ///xixi/haha
fs模块
文件处理模块,可以读文件,也可以写文件
fs.readfile(); //读取文件内容 fs.readdir(); //读取文件夹名 fs.appendfile(); //追加文件 fs.writefile(); //写入文件(覆盖原有的) fs.rename(); //修改文件名
自定义模块
每一个js文件中可以看成是一个小小的模块
require()谁,就会执行谁。就相当于调用一个函数。a require b, 先执行b全部语句,然后执行a的剩余语句。
require('./test/a.js');
每个js文件就是一个闭包,声明的函数、变量只在这个js文件内部有定义。
a require了 b , 那么b里面的所有路径都要按照a的路径写。
如果需要使用到其它文件中的变量,使用exports暴露出去。
exports.*** = ***; testa .js var a = 100; exports.a = a;
主文件
var testa = requrie('./testa.js');
console.log( testa.a );
暴露唯一的接口,module.exports ,一般使用到构造函数。
如果只有写文件载入,会去默认文件夹下:node_modules 寻找是否有当前需要载入的文件
require('test.js');
也可以直接省略路径、省略文件名,只写文件夹名
require('aa');
实际上引用的是node_moduels文件夹里面的aa文件夹里面的index.js文件。
一般第三方模块,都放入node_modules文件夹中。
package.json
配置信息:
{
"name": "my_package", //项目名字
"version": "1.0.0", //版本号
"main": "index.js", //入口文件
"keywords": [], //关键词,就是搜索什么npm上能够显示你
"author": "ag_dubs", //作者
"license": "isc", //版权协议
"repository": { //代码托管仓库,这个会自动生成一个连接
"type": "git",
"url": "https://github.com/ashleygwilliams/my_package.git"
},
"bugs": { //如果发现bug应该交给谁
"url": "https://github.com/ashleygwilliams/my_package/issues"
},
"dependencies": {
"underscore": "*",
"date-format" : "0.0.2"
},
"homepage": "https://github.com/ashleygwilliams/my_package" //个人网站
}
最重要的信息是:依赖
{
"dependencies": {
"underscore": "*",
"date-format" : "^0.0.2"
}
}
formidable
处理post请求
// formidable 语法
var form = new formidable.incomingform();
// 设置上传路径
form.uploaddir = "./uploads";
form.parse(req, function(err, fields, files) {
// fields是普通域,就是普通的文本框、单选按钮、复选按钮、textarea都存在这个对象里面
// files是上传的文件信息
var newname = df('yyyymmddhhmmsssss', new date());
fs.rename(files.touxiang.path , "./uploads/" + newname + ".jpg",function(err){
if(err){
res.end("error");
return ;
}
});
res.end("ok");
});
爬虫初级
需要的npm包:
- express
- request (后端发送请求的模块)
- cheerio (像前端一样操作拉取回来的数据)
爬虫以及robots协议介绍:
- 爬虫,是中自动获取网页内容的程序。是搜索引擎的重要组成部分,因此搜索引擎优化很大程度上就是针对爬虫而做出的优化。
- robots.txt是一个文本文件,robots.txt是一个协议,不是一个命令。robots.txt是爬虫要查看的第一个文件。robots.txt文件告诉爬虫在服务器上什么文件是可以被查看的,搜索机器人就会按照该文件中的内容来确定访问的范围。

var express = require('express');
var app = express();
var cheerio = require('cheerio');
app.get('/', function(req, res){
var request = require('request');
request('https://linxingzhang.com', function(err, response, body) {
if (!err && response.statuscode == 200) {
$ = cheerio.load(body); // 和jquery的$('body') 一样
res.json({
panel: $('#link-panel li').length
});
}
});
});
app.listen(3000);
使用supervisor启动
> supervisor start app.js
常用npm包
| 模块名 | 链接地址 | 简介 |
|---|---|---|
| async | 异步操作管理 | |
| bl | 二进制数据解析 | |
| bluebird | 异步操作管理 | |
| browserify | 发布浏览器可用的包 | |
| bunyan | 日志(logging)管理 | |
| chai | 断言 | |
| chalk | 命令行彩色输出 | |
| co | 异步流程管理 | |
| colors | 命令行彩色输出 | |
| commander | 命令行工具 | |
| debug | debug输出器 | |
| dockerode | docker管理 | |
| duplexify | stream流操作工具 | |
| event-stream | stream流操作工具 | |
| express | server服务器框架 | |
| hapi | server服务器框架 | |
| koa | server服务器框架 | |
| glob | 文件名匹配 | |
| grunt | 构建工具 | |
| gulp | 构建工具 | |
| hyperquest | 轻量级http客户端 | |
| istanbul | 测试用例覆盖率分析 | |
| jsonstream | jsonstream | stream流管理工具 |
| levelup | leveldb | |
| lodash | 函数式编程工具 | |
| log4js | 日志(logging)管理工具 | |
| minimatch | 文件名匹配 | |
| minimist | 命令行操作 | |
| mocha | 单元测试 | |
| moment | 日期时间输出 | |
| mongodb | mongodb | |
| mysql | mysql | |
| nconf | 配置工具 | |
| needle | 轻量级http客户端 | |
| node-fetch | fetch api | |
| nodemailer | email客户端 | |
| passport | 登录和认证 | |
| pg | postgres | |
| pump | stream流管理工具 | |
| redis | redis | |
| request | http客户端 | |
| restify | rest api搭建 | |
| socket.io | websocket实时通信 | |
| split2 | stream流管理工具 | |
| tape | 单元测试 | |
| through2 | stream流管理工具 | |
| underscore | 函数式编程工具 | |
| ws | websockets | |
| xml2js | xml转换为javascript | |
| http-server | 命令行的http服务器 | |
| nrm | 更改npm下载源 | |
| node-inspector | node调试 | |
| supervisor | 检测node进程的服务 | |
| nodemon | 在文件有变化之后会自动重启服务 |
希望本文所述对大家node.js程序设计有所帮助。
