Node.js
2019-08-12 本文已影响0人
小凡凡520
一、说明
1、Node.js 就是运行在服务端的 JavaScript
2、Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台
3、Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。
如果我们使用PHP来编写后端的代码时,需要Apache 或者 Nginx 的HTTP 服务器,并配上 mod_php5 模块和php-cgi。
二、安装
三、Node.js 应用的组成部分
- 引入 required 模块
我们可以使用 require 指令来载入 Node.js 模块 - 创建服务器
服务器可以监听客户端的请求,类似于 Apache 、Nginx 等 HTTP 服务器 - 接收请求与响应请求
服务器很容易创建,客户端可以使用浏览器或终端发送 HTTP 请求,服务器接收请求后返回响应数据
var http = require('http');
http.createServer(function (request, response) {
// 发送 HTTP 头部
// HTTP 状态值: 200 : OK
// 内容类型: text/plain
response.writeHead(200, {'Content-Type': 'text/plain'});
// 发送响应数据 "Hello World"
response.end('11111Hello World\n');
}).listen(8888);
// 终端打印如下信息
console.log('Server running at http://127.0.0.1:8888/');
四、基本使用
Node.js REPL(交互式解释器)
// 表达式:
$ node
> 1 +4
5
// 使用变量
$ node
> x = 10
10
// 多行表达式
$ node
> do {
... x++;
... console.log("x: " + x);
... } while ( x < 5 );
// 下划线(_)变量
$ node
> var x = 10
undefined
> var y = 20
undefined
> x + y
30
> var sum = _
undefined
> console.log(sum)
30
REPL 命令
快捷键 | 说明 |
---|---|
ctrl + c | 退出当前终端 |
ctrl + c 按下两次 | 退出 Node REPL |
ctrl + d | 退出 Node REPL |
向上/向下 键 | 查看输入的历史命令 |
tab 键 | 列出当前命令 |
.help | 列出使用命令 |
.break | 退出多行表达式 |
.clear | 退出多行表达式 |
.save filename | 保存当前的 Node REPL 会话到指定文件 |
.load filename | 载入当前 Node REPL 会话的文件内容 |
五、回调
同步
var fs = require('fs');
var data = fs.readFileSync('/Users/chen_fan/Desktop/mmm.rtf');
console.log(data.toString());
异步
var fs = require('fs');
fs.readFile("/Users/chen_fan/Desktop/mmm.rtf",function (err,data) {
if (err) return;
console.log(data.toString());
console.log('2');
})
console.log('1');
六、事件循环
1、Node.js 是单进程单线程应用程序,但是因为 V8 引擎提供的异步执行回调接口,通过这些接口可以处理大量的并发,所以性能非常高
2、Node.js 几乎每一个 API 都是支持回调函数的。
3、Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现
4、Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数
事件驱动程序
1、Node.js 使用事件驱动模型,当web server接收到请求,就把它关闭然后进行处理,然后去服务下一个web请求。
2、当这个请求完成,它被放回处理队列,当到达队列开头,这个结果被返回给用户
3、这个模型非常高效可扩展性非常强,因为webserver一直接受请求而不等待任何读写操作。(这也被称之为非阻塞式IO或者事件驱动IO)
在事件驱动模型中,会生成一个主循环来监听事件,当检测到事件时触发回调函数。
var events = require('events');
var eventEmitter = new events.EventEmitter();
var connectHandle = function connected() {
console.log("连接成功");
eventEmitter.emit('data_received');
}
eventEmitter.on('connection',connectHandle);
eventEmitter.on('data_received',function() {
console.log("数据接收成功");
})
eventEmitter.emit("connection");
console.log('完成')
var EventEmitter = require('events').EventEmitter;
var event = new EventEmitter();
event.on('some_event',function () {
console.log('事件触发');
});
setTimeout(function () {
event.emit('some_event');
});
var events = require('events');
var emitter = new events.EventEmitter();
emitter.on('some_event',function (v1, v2) {
console.log(v1 + v2);
});
emitter.on('some_event',function (v1, v2) {
console.log(v1,v2);
});
emitter.emit('some_event',1,2);
var events = require('events');
var emitter = new events.EventEmitter();
var call = function() {
console.log('add');
};
emitter.addListener('ss',call);
emitter.removeListener('ss',call);
emitter.emit('ss');
var events = require('events');
var emitter = new events.EventEmitter();
var listener1 = function () {
console.log('test1');
};
var listener2 = function () {
console.log('test2');
};
emitter.addListener('test',listener1);
emitter.on('test',listener2);
console.log(emitter.listenerCount('test'));
emitter.emit('test');
七、缓冲区
const buf = Buffer.from('chenfan','ascii');
console.log(buf.toString('hex'));
console.log(buf.toString('base64'));
编码 | 说明 |
---|---|
ascii | 仅支持 7 位 ASCII 数据。如果设置去掉高位的话,这种编码是非常快的 |
utf8 | 多字节编码的 Unicode 字符。许多网页和其他文档格式都使用 UTF-8 |
utf16le | 2 或 4 个字节,小字节序编码的 Unicode 字符。支持代理对(U+10000 至 U+10FFFF) |
ucs2 | utf16le 的别名 |
base64 | Base64 编码 |
latin1 | 一种把 Buffer 编码成一字节编码的字符串的方式 |
binary | latin1 的别名 |
hex | 将每个字节编码为两个十六进制字符 |
// 创建一个长度为 10、且用 0 填充的 Buffer。
const buf1 = Buffer.alloc(10);
// 创建一个长度为 10、且用 0x1 填充的 Buffer。
const buf2 = Buffer.alloc(10, 1);
// 创建一个长度为 10、且未初始化的 Buffer。
// 这个方法比调用 Buffer.alloc() 更快,
// 但返回的 Buffer 实例可能包含旧数据,
// 因此需要使用 fill() 或 write() 重写。
const buf3 = Buffer.allocUnsafe(10);
// 创建一个包含 [0x1, 0x2, 0x3] 的 Buffer。
const buf4 = Buffer.from([1, 2, 3]);
// 创建一个包含 UTF-8 字节 [0x74, 0xc3, 0xa9, 0x73, 0x74] 的 Buffer。
const buf5 = Buffer.from('tést');
// 创建一个包含 Latin-1 字节 [0x74, 0xe9, 0x73, 0x74] 的 Buffer。
const buf6 = Buffer.from('tést', 'latin1');
buf1.write('123');
buf1.toString('utf8')
八、流
读数据
var fs = require('fs');
var data = '';
var readerStream = fs.createReadStream('/Users/chen_fan/Desktop/HH.h')
readerStream.setEncoding('UTF-8');
readerStream.on('data',function (chunk) {
data += chunk;
});
readerStream.on('end',function () {
console.log(data);
});
readerStream.on('error',function (err) {
console.log(err.stack);
});
写数据
var fs = require('fs');
var data = 'test';
var writeStream = fs.createWriteStream('/Users/chen_fan/Desktop/mmm.rtf');
writeStream.write(data,'utf8');
writeStream.end();
writeStream.on('finish',function () {
console.log('ok');
});
writeStream.on('error',function (err) {
console.log(err.stack);
});
管道流
var fs = require('fs');
var readStream = fs.createReadStream('/Users/chen_fan/Desktop/mmm.rtf');
var writeStream = fs.createWriteStream('/Users/chen_fan/Desktop/m1.rtf');
readStream.pipe(writeStream);
链式流
var fs = require("fs");
var zlib = require('zlib');
// 压缩 input.txt 文件为 input.txt.gz
fs.createReadStream('input.txt')
.pipe(zlib.createGzip())
.pipe(fs.createWriteStream('input.txt.gz'));
console.log("文件压缩完成。");
var fs = require("fs");
var zlib = require('zlib');
// 解压 input.txt.gz 文件为 input.txt
fs.createReadStream('input.txt.gz')
.pipe(zlib.createGunzip())
.pipe(fs.createWriteStream('input.txt'));
console.log("文件解压完成。");
九、模块系统
接口
exports.world = function() {
console.log('Hello World');
};
exports.hh = function () {
console.log('test');
}
var hello = require('./hello');
hello.hh();
模块
//hello.js
function Hello() {
var name;
this.setName = function(thyName) {
name = thyName;
};
this.sayHello = function() {
console.log('Hello ' + name);
};
};
module.exports = Hello;
var Hello = require('./hello');
var hello = new Hello();
hello.setName('chenfan');
hello.sayHello();
十、函数
普通函数
function say(word) {
console.log(word)
};
function test(some, value) {
some(value);
};
test(say,'chenfan');
匿名函数
function test(some, value) {
some(value);
}
test(function (word) {
console.log(word)
},'chenfan');
var http = require('http');
http.createServer(function (request, response) {
response.writeHead(200,{'Content-Type':'text/plain'});
response.write('chenfan');
response.end();
}).listen(8888);
var http = require('http');
function onRequest(request,response){
response.writeHead(200,{'Content-Type':'text/plain'});
response.write('chenfan');
response.end();
}
http.createServer(onRequest).listen(8888);
十一、路由
// server.js
var http = require("http");
var url = require("url");
function start() {
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
exports.start = start;
// router.js
function route(pathname) {
console.log("About to route a request for " + pathname);
}
exports.route = route;
// main.js
var server = require("./server");
var router = require("./router");
server.start(router.route);
十二、常用工具
var util = require('util');
function Base() {
this.name = 'base';
this.base = 1991;
this.sayHello = function() {
console.log('Hello ' + this.name);
};
}
Base.prototype.showName = function() {
console.log(this.name);
};
function Sub() {
this.name = 'sub';
}
util.inherits(Sub, Base);
var objBase = new Base();
objBase.showName();
objBase.sayHello();
console.log(objBase);
var objSub = new Sub();
objSub.showName();
//objSub.sayHello();
console.log(objSub);
var util = require('util');
function Person() {
this.name = 'byvoid';
this.toString = function() {
return this.name;
};
}
var obj = new Person();
console.log(util.inspect(obj));
console.log(util.inspect(obj, true));
var util = require('util');
util.isArray([])
// true
util.isArray(new Array)
// true
util.isArray({})
// false
var util = require('util');
util.isRegExp(/some regexp/)
// true
util.isRegExp(new RegExp('another regexp'))
// true
util.isRegExp({})
// false
var util = require('util');
util.isDate(new Date())
// true
util.isDate(Date())
// false (without 'new' returns a String)
util.isDate({})
// false
var util = require('util');
util.isError(new Error())
// true
util.isError(new TypeError())
// true
util.isError({ name: 'Error', message: 'an error occurred' })
// false
十三、文件系统
读取文件
var fs = require("fs");
// 异步读取
fs.readFile('input.txt', function (err, data) {
if (err) {
return console.error(err);
}
console.log("异步读取: " + data.toString());
});
// 同步读取
var data = fs.readFileSync('input.txt');
console.log("同步读取: " + data.toString());
console.log("程序执行完毕。");
打开文件
var fs = require("fs");
// 异步打开文件
console.log("准备打开文件!");
fs.open('input.txt', 'r+', function(err, fd) {
if (err) {
return console.error(err);
}
console.log("文件打开成功!");
});
flag | 说明 |
---|---|
r | 以读取模式打开文件。如果文件不存在抛出异常 |
r+ | 以读写模式打开文件。如果文件不存在抛出异常 |
rs | 以同步的方式读取文件 |
rs+ | 以同步的方式读取和写入文件 |
w | 以写入模式打开文件,如果文件不存在则创建 |
wx | 类似 'w',但是如果文件路径存在,则文件写入失败 |
w+ | 以读写模式打开文件,如果文件不存在则创建 |
wx+ | 类似 'w+', 但是如果文件路径存在,则文件读写失败 |
a | 以追加模式打开文件,如果文件不存在则创建 |
ax | 类似 'a', 但是如果文件路径存在,则文件追加失败 |
a+ | 以读取追加模式打开文件,如果文件不存在则创建 |
ax+ | 类似 'a+', 但是如果文件路径存在,则文件读取追加失败 |
获取文件信息
var fs = require('fs');
fs.stat('/Users/liuht/code/itbilu/demo/fs.js', function (err, stats) {
console.log(stats.isFile()); //true
})
十四、GET / POST
var http = require('http');
var url = require('url');
var util = require('util');
http.createServer(function(req, res){
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end(util.inspect(url.parse(req.url,true)));
}).listen(3000);
var http = require('http');
var url = require('url');
var util = require('util');
http.createServer(function(req, res){
res.writeHead(200, {'Content-Type': 'text/plain'});
// 解析 url 参数
var params = url.parse(req.url, true).query;
res.write("网站名:" + params.name);
res.write("\n");
res.write("网站 URL:" + params.url);
res.end();
}).listen(3000);
var http = require('http');
var querystring = require('querystring');
var postHTML =
'<html><head><meta charset="utf-8"><title>菜鸟教程 Node.js 实例</title></head>' +
'<body>' +
'<form method="post">' +
'网站名: <input name="name1"><br>' +
'网站 URL: <input name="url1"><br>' +
'<input type="submit">' +
'</form>' +
'</body></html>';
http.createServer(function (req, res) {
var body = "";
req.on('data', function (chunk) {
body += chunk;
});
req.on('end', function () {
// 解析参数
body = querystring.parse(body);
// 设置响应头部信息及编码
res.writeHead(200, {'Content-Type': 'text/html; charset=utf8'});
if(body.name1 && body.url1) { // 输出提交的数据
res.write("网站名:" + body.name1);
res.write("<br>");
res.write("网站 URL:" + body.url1);
} else { // 输出表单
res.write(postHTML);
}
res.end();
});
}).listen(3000);