nodejs
nodejs是基于谷歌Chrome的V8引擎(JavaScript引擎)的服务端平台(或语言)。node于2009由
Ryan Dahl开发,可以轻松构建快速、可扩展的网络应用,它使用事件驱动、非阻塞IO模型让其变得
轻量和高效,可以完美跨平台支持数据实时交互的应用。
nodejs = 运行时环境 + JavaScript类库
特征
异步+事件驱动(Asynchronous and Event Driven)
node的所有API都是异步的(非阻塞,任何API不会等待数据返回)。node服务端通过事件通知机制,来
获得API的响应。
非常快(Very Fast)
基于谷歌Chrome的V8引擎,node类库可以快速执行代码。
单线程,但高扩展(Single Threaded but Highly Scalable)
node是基于单线程模型的,事件机制可以以非阻塞模式让node高扩展,而不是像传统应用创建有限的线程
去处理请求。node可以处理比传统服务器(Apache HTTP Server)更多量级的请求。
没有缓冲(No Buffering)
node不会缓冲任何数据,而是简单将数据放到chunk中。
适用&不适用场景
适用
I/O密集型应用
数据流型应用
数据实时交互型应用
JSON API类型应用
单页面型应用
不适用
CPU密集型应用
使用
$ cd /tmp
$ wget http://nodejs.org/dist/v6.3.1/node-v6.3.1-linux-x64.tar.gz
$ tar xvfz node-v6.3.1-linux-x64.tar.gz
$ mkdir -p /usr/local/nodejs
$ mv node-v6.3.1-linux-x64/* /usr/local/nodejs
node test.js
实例
概念
导入必须模块(Import required modules)
通过require指令导入node模块
创建服务(Create Server)
服务类似于Apache HTTP Server,是可以监听和影响客户端的请求的
请求&响应(Read request and return response)
接受请求,并做响应
// 引入模块
var http = require("http");
// 创建服务
http.createServer(function (request, response) {
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end('Hello node \n');
}).listen(8888);
console.log('Server running at http://127.0.0.1:8888/')
包管理
npm, Node Package Manager
命令行
# 本地安装
npm install <Module Name>
# 全局安装
npm install <Module Name> -g
# 查看
npm ls -g
# 卸载
npm uninstall <Module Name>
# 搜索
npm search <Module Name>
package.json
定义依赖的包,类似maven的pom.xml
name: 包名称
version: 包版本
description: 包描述
homepage: 包首页
author: 包作者
contributors: 包贡献者
dependencies: 依赖列表(npm自动安装这些依赖)
repository: 包仓库地址
main: 包主要入口
keywords: 包关键字
创建包
npm init
npm adduser
npm publish
回调
回调类似一个异步函数,在任务完成时触发。node需要大量回调,所有API都支持回调。
// blocking
var fs = require("fs")
var data = fs.readFileSync('t.txt');
console.log(data.toString());
console.log("end");
// non-blocking
fs.readFile('t.txt', function(error, data){
if (error){
return console.log(error);
}
console.log(data.toString());
});
console.log("end");
事件
node虽然是单线程,但是可以通过事件和回调支持并发(观察者模式)。
事件驱动
函数类似观察者,当事件触发后,函数就会执行。
var events = require('events');
var eventEmitter = new events.EventEmitter();
var connectHandler = function connected(){
console.log('connection successful');
eventEmitter.emit('data_received');
}
eventEmitter.on('connection', connectHandler);
eventEmitter.on('data_received', function(){
console.log('data received successful');
});
eventEmitter.emit('connection');
console.log('end');
EventEmitter
addListener(event,listener)
on(event,listner)
once(event,listner)
removeAllListeners([event])
setMaxListeners(n)
listeners(event)
emit(event, [arg1], [arg2], [..])
listenerCount(emmiter, event)
newListner(event, listener)
removeListener(event, listener)
例子
var events = require('events');
var eventEmitter = new events.EventEmitter();
// listener #1
var listner1 = function listner1() {
console.log('listner1 executed.');
}
// listener #2
var listner2 = function listner2() {
console.log('listner2 executed.');
}
// Bind the connection event with the listner1 function
eventEmitter.addListener('connection', listner1);
// Bind the connection event with the listner2 function
eventEmitter.on('connection', listner2);
var eventListeners = require('events').EventEmitter.listenerCount
(eventEmitter,'connection');
console.log(eventListeners + " Listner(s) listening to connection event");
// Fire the connection event
eventEmitter.emit('connection');
// Remove the binding of listner1 function
eventEmitter.removeListener('connection', listner1);
console.log("Listner1 will not listen now.");
// Fire the connection event
eventEmitter.emit('connection');
eventListeners = require('events').EventEmitter.listenerCount(eventEmitter,'connection');
console.log(eventListeners + " Listner(s) listening to connection event");
console.log("Program Ended.");
缓冲
node提供Buffer来存储原始数据(类似整型数组),buffer是一个全局类,可以不用import模块。
命令行
# 创建
var buf = new Buffer(10);
var buf = new Buffer([10, 20, 30, 40, 50]);
var buf = new Buffer("Simply Easy Learning", "utf-8");
# 写数据
buf.write(string[, offset][, length][, encoding])
string:字符串数据
offset:开始写入位置, 默认0
length:写入字节数量, 默认buffer.length
encoding: 编码,默认utf8
# 读数据
buf.toString([encoding][, start][, end])
encoding:编码,默认utf8
start: 开始读取位置,默认0
end:结束读取位置,默认读整个buffer
# 转json
buf.toJSON()
# 整合多个buffer
Buffer.concat(list[, totalLength])
# 比较buffer
buf.compare(otherBuffer);
# 复制buffer
buf.copy(targetBuffer[, targetStart][, sourceStart][, sourceEnd])
# 截取buffer
buf.slice([start][, end])
流
Streams:从源头读取数据或写数据至目标。
# 类型
Readable: 读取
Writable: 写入
Duplex: 读写
Transform: 读写,输出是基于输入计算的
# 事件
data: 数据可读
end: 数据读取完毕
error: 读写出错
finish: 所有数据被刷新
var fs = require("fs");
// Create a readable stream
var readerStream = fs.createReadStream('input.txt');
// Create a writable stream
var writerStream = fs.createWriteStream('output.txt');
// Pipe the read and write operations
// read input.txt and write data to output.txt
readerStream.pipe(writerStream);
console.log("Program Ended");
文件系统
var fs = require(“fs”);
var fs = require("fs");
// Asynchronous read
fs.readFile('input.txt', function (err, data) {
if (err) {
return console.error(err);
}
console.log("Asynchronous read: " + data.toString());
});
// Synchronous read
var data = fs.readFileSync('input.txt');
console.log("Synchronous read: " + data.toString());
console.log("Program Ended");
API
# 文件读写
fs.open(path, flags[, mode], callback)
path: 路径
flags:
r(读,文件不存在抛异常)
r+(读写,文件不存在抛异常)
rs(同步读)
rs+(同步读写)
w(写,文件不存在创建,文件存在删除)
wx(同上,但文件不存在失败)
w+(读写,文件不存在创建,文件存在删除)
wx+(读写,文件不存在失败)
a(追加,文件不存在创建)
ax(追加,文件不存在失败)
a+(读&追加,文件不存在创建)
ax+(读&追加,文件不存在失败)
mode:权限,类似linux。默认0666(读写)
callback: 回调函数,两个参数(err,fd)
# 文件信息
fs.stat(path, callback)
callback: 回调函数,两个参数(err,stats)
stats.isFile()
stats.isDirectory()
stats.isBlockDevice()
stats.isCharacterDevice()
stats.isSymbolicLink()
stats.isFIIO
stats.isSocket()
# 文件写
fs.writeFile(filename, data[, options], callback)
# 文件读
fs.read(fd, buffer, offset, length, position, callback)
# 关闭文件
fs.close(fd, callback)
# 删除文件
fs.ftruncate(fd, len, callback)
# 删除文件
fs.unlink(path, callback)
# 创建目录
fs.mkdir(path[, mode], callback)
# 读取目录
fs.readdir(path, callback)
# 删除目录
fs.rmdir(path, callback)
实例
# 文件读写
var fs = require("fs");
// Asynchronous - Opening File
console.log("Going to open file!");
fs.open('input.txt', 'r+', function(err, fd) {
if (err) {
return console.error(err);
}
console.log("File opened successfully!");
});
# 文件信息
console.log("Going to get file info!");
fs.stat('input.txt', function (err, stats) {
if (err) {
return console.error(err);
}
console.log(stats);
console.log("Got file info successfully!");
// Check file type
console.log("isFile ? " + stats.isFile());
console.log("isDirectory ? " + stats.isDirectory());
});
全局对象
node的全局对象,可以在所有模块可用。不需要在项目中引用,直接可使用。
__filename
文件全路径
__dirname
文件路径
setTimeout(cb, ms)
延迟执行
clearTimeout(t)
清除延迟
setInterval(cb, ms)
定时执行
Console
标准输出
Process
进程相关
常用模块
OS Module: 操作系统
Path Module: 文件路径
Net Module:网络
DNS Module: 域名解析
Domain Module: IO操作
web模块
web应用架构
Client:客户端
Server: 服务端
Business: 业务端
Data: 数据端
实例
# 服务端
var http = require('http');
var fs = require('fs');
var url = require('url');
// Create a server
http.createServer( function (request, response) {
// Parse the request containing file name
var pathname = url.parse(request.url).pathname;
// Print the name of the file for which request is made.
console.log("Request for " + pathname + " received.");
// Read the requested file content from file system
fs.readFile(pathname.substr(1), function (err, data) {
if (err) {
console.log(err);
// HTTP Status: 404 : NOT FOUND
// Content Type: text/plain
response.writeHead(404, {'Content-Type': 'text/html'});
} else {
//Page found
// HTTP Status: 200 : OK
// Content Type: text/plain
response.writeHead(200, {'Content-Type': 'text/html'});
// Write the content of the file to response body
response.write(data.toString());
}
// Send the response body
response.end();
});
}).listen(8081);
// Console will print the message
console.log('Server running at http://127.0.0.1:8081/');
# 客户端
var http = require('http');
// Options to be used by request
var options = {
host: 'localhost',
port: '8081',
path: '/index.htm'
};
// Callback function is used to deal with response
var callback = function(response) {
// Continuously update stream with data
var body = '';
response.on('data', function(data) {
body += data;
});
response.on('end', function() {
// Data received completely.
console.log(body);
});
}
// Make a request to the server
var req = http.request(options, callback);
req.end();
Express框架
Express是一款常用的基于Node的web应用框架,内置了一些组件可以提高开发效率。
1. 允许设置中间件响应HTTP请求
2. 定义了基于HTTP的URL和Method的路由表(请求分发器)
3. 允许基于参数和模块动态渲染页面
安装
npm install express --save
npm install body-parser --save
npm install cookie-parser --save
npm install multer --save
body-parser: 处理请求和响应body,比如json、text、form data
cookie-parser: 处理cookie相关
multer: 文件上传,处理multipart/form-data
实例
var express = require('express');
var app = express();
app.get('/', function(req, res){
console.log();
res.send('Hello Express Get');
})
app.post('/', function(req, res){
console.log('Got a POST request for the homepage');
res.send('Hello Express Post');
})
// This responds a GET request for the /list_user page.
app.get('/list_user', function (req, res) {
console.log("Got a GET request for /list_user");
res.send('Page Listing');
})
// This responds a GET request for abcd, abxcd, ab123cd, and so on
app.get('/ab*cd', function(req, res) {
console.log("Got a GET request for /ab*cd");
res.send('Page Pattern Match');
})
// static resource
app.use(express.static('public'))
app.get('/index.htm', function (req, res) {
res.sendFile( __dirname + "/" + "index.htm" );
})
// get
app.get('/process_get', function (req, res) {
// Prepare output in JSON format
response = {
first_name:req.query.first_name,
last_name:req.query.last_name
};
console.log(response);
res.end(JSON.stringify(response));
})
// Create application/x-www-form-urlencoded parser
var bodyParser = require('body-parser');
var urlencodedParser = bodyParser.urlencoded({ extended: false })
// post
app.post('/process_post', urlencodedParser, function (req, res) {
// Prepare output in JSON format
response = {
first_name:req.body.first_name,
last_name:req.body.last_name
};
console.log(response);
res.end(JSON.stringify(response));
})
// file
var fs = require("fs");
var multer = require('multer');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(multer({ dest: '/tmp/'}));
app.post('/file_upload', function (req, res) {
console.log(req.files.file.name);
console.log(req.files.file.path);
console.log(req.files.file.type);
var file = __dirname + "/" + req.files.file.name;
fs.readFile( req.files.file.path, function (err, data) {
fs.writeFile(file, data, function (err) {
if( err ) {
console.log( err );
} else {
response = {
message:'File uploaded successfully',
filename:req.files.file.name
};
}
console.log( response );
res.end( JSON.stringify( response ) );
});
});
})
// cookie
var cookieParser = require('cookie-parser')
app.use(cookieParser())
app.get('/', function(req, res) {
console.log("Cookies: ", req.cookies)
})
var server = app.listen(8889, function(){
var host = server.address().address
var port = server.address().port
console.log("app listening at http://%s:%s", host, port);
})
扩展
node虽然是单线程,但是也可以利用CPU多核能力,通过子线程来扩展能力
node提供了child_process模块专门处理子线程
命令:
child_process.exec(command[, options], callback): 运行命令
child_process.spawn(command[, args][, options]):开启子线程运行命令
child_process.fork(modulePath[, args][, options]):spawn的特殊场景,开启子线程运行命令
实例
const fs = require('fs');
const child_process = require('child_process');
// exec
for(var i=0; i<3; i++) {
var workerProcess = child_process.exec('node support.js '+i,function
(error, stdout, stderr) {
if (error) {
console.log(error.stack);
console.log('Error code: '+error.code);
console.log('Signal received: '+error.signal);
}
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
});
workerProcess.on('exit', function (code) {
console.log('Child process exited with exit code '+code);
});
}
// spawn
for(var i = 0; i<3; i++) {
var workerProcess = child_process.spawn('node', ['support.js', i]);
workerProcess.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
workerProcess.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
workerProcess.on('close', function (code) {
console.log('child process exited with code ' + code);
});
}
// fork
for(var i=0; i<3; i++) {
var worker_process = child_process.fork("support.js", [i]);
worker_process.on('close', function (code) {
console.log('child process exited with code ' + code);
});
}
JXcore打包
JXcore一个开源的,将源代码打包加密至JX包。
安装
# 下载
wget https://s3.amazonaws.com/nodejx/jx_rh64.zip
# 解压&安装
unzip jx_rh64.zip
cp jx_rh64/jx /usr/bin
export PATH=$PATH:/usr/bin
jx --version
命令
# 打包
jx package index.js index
# 运行&启动
node index.js command_line_arguments
jx index.jx command_line_arguments