nodejs笔记

菜鸟教程

简介

简单的说 Node.js 就是运行在服务端的 JavaScript。
Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台。
Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。

安装

参考菜鸟教程

NPM使用介绍

新版的nodejs已经集成了npm,可以通过查看版本号测试是否安装成功:

$ npm -v
4.2.0

使用淘宝NPM镜像

$ npm install -g cnpm --registry=https://registry.npm.taobao.org

// 使用cnpm来安装模块
$ cnpm install [name]

安装模块

$ npm install <Module Name>       #本地
$ npm install <Module Name> -g    #全局

查看安装信息

$ npm list -g

查看某个模块的版本号

$ npm list grunt

卸载模块

$ npm uninstall express

更新模块

$ npm update express

搜索模块

$ npm search express

创建模块,会生成 package.json 文件

$ npm init

版本号

语义版本号分为X.Y.Z三位,分别代表主版本号、次版本号和补丁版本号。

  1. 如果只是修复bug,需要更新Z位。
  2. 如果是新增了功能,但是向下兼容,需要更新Y位。
  3. 如果有大变动,向下不兼容,需要更新X位。

回调函数

阻塞代码

var fs = require("fs");

var data = fs.readFileSync('input.txt');

console.log(data.toString());
console.log("程序执行结束!");

非阻塞代码

var fs = require("fs");

fs.readFile('input.txt', function (err, data) {
    if (err) return console.error(err);
    console.log(data.toString());
});

console.log("程序执行结束!");

阻塞实例在文件读取完后才执行完程序。
非阻塞实例我们不需要等待文件读取完,这样就可以在读取文件时同时执行接下来的代码,大大提高了程序的性能。
阻塞是按顺序执行的,而非阻塞是不需要按顺序的,所以如果需要处理回调函数的参数,我们就需要写在回调函数内。

事件循环

  1. nodejs是单进程单线程应用程序,通过事件回调支持并发,所以性能非常高。
  2. nodejs的每一个API都是异步的,并作为一个独立线程运行,使用异步函数调用,并处理并发。
  3. nodejs基本上所有的事件机制都是用设计模式中的观察者模式实现。
  4. nodejs单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数。
var events = require('events');
var eventEmitter = new events.EventEmitter();
// 监听器1
var listener1 = function listener1(){
    console.log('监听器 listener1 执行。');
}
// 监听器2
var listener2 = function listener2(){
    console.log('监听器 lisrener2 执行。');
}
// 绑定连接事件,处理函数为listener1
eventEmitter.addListener('connection',listener1);
// 绑定连接事件,处理函数为listener1
eventEmitter.addListener('connection',listener2);

var eventListeners = require('events').EventEmitter.listenerCount(eventEmitter,'connection');
console.log(eventListeners + ' 个监听器监听连接事件。');
// 处理连接事件
eventEmitter.emit('connection');
// 移除监绑定的 listener1 函数
eventEmitter.removeListener('connection',listener1);
console.log('listener1 不再受监听。');
// 触发连接事件
eventEmitter.emit('connection');

eventListeners = require('events').EventEmitter.listenerCount(eventEmitter,'connection');
console.log(eventListeners + ' 个监听器监听连接事件。');

eventEmitter.emit('error');
console.log('程序执行完成。');



// 执行结果
$ node main.js
2 个监听器监听连接事件。
监听器 listener1 执行。
监听器 listener2 执行。
listener1 不再受监听。
监听器 listener2 执行。
1 个监听器监听连接事件。
程序执行完毕。

Buffer(缓冲区)

在 Node.js中,定义了一个 Buffer 类,该类用来创建一个专门存放二进制数据的缓存区。

创建Buffer类

var buf = new Buffer([10,20,30,40,50]);;
console.log(buf);
// <Buffer 0a 14 1e 28 32>

var buf2 = new Buffer('www.runoob.com','utf-8');
console.log(buf2);
// <Buffer 77 77 77 2e 72 75 6e 6f 6f 62 2e 63 6f 6d>

var buf3 = new Buffer(10);
console.log(buf3);
// <Buffer 00 00 00 00 00 00 00 00 00 00>

写入缓冲区

var len = buf3.write('www.runoob.com');
console.log('写入字节数:' + len);

从缓冲区读取数据

console.log(buf.toString('ascii'));
console.log(buf.toString('ascii',0,5));
console.log(buf.toString('utf8',0,5));
console.log(buf.toString(undefined,0,5));
console.log(buf.toJSON());

缓冲区合并

var buffer1 = new Buffer('菜鸟教程');
var buffer2 = new Buffer('www.runoob.com');
var buffer3 = Buffer.concat([buffer1,buffer2]);
console.log('buffer3 内容: '+buffer3.toString());

缓冲区比较

var buff1 = new Buffer('ABC');
var buff2 = new Buffer('ABCD');
var result = buff1.compare(buff2);

if(result < 0){
    console.log(buff1 + ' 在 ' + buff2 + '之前');
}else if(result == 0){
    console.log(buff1 + ' 与 ' + buff2 + '相同');
}else{
    console.log(buff1 + ' 在 ' + buff2 + '之后');
}

拷贝缓冲区

var b1 = new Buffer('ABC');
var b2 = new Buffer(3);
b1.copy(b2);
console.log('b2 content: '+b2.toString());

缓冲区裁剪

var buffer1 = new Buffer('runoob');
// 剪切缓冲区
var buffer2 = buffer1.slice(0,2);
console.log("buffer2 content: " + buffer2.toString());

缓冲区长度

var buffer = new Buffer('www.runoob.com');
//  缓冲区长度
console.log("buffer length: " + buffer.length);

Stream(流)

Stream 是一个抽象接口,Node 中有很多对象实现了这个接口。例如,对http 服务器发起请求的request 对象就是一个 Stream,还有stdout(标准输出)。
Node.js,Stream 有四种流类型:

  1. Readable - 可读操作。
  2. Writable - 可写操作。
  3. Duplex - 可读可写操作.
  4. Transform - 操作被写入数据,然后读出结果。

所有的 Stream 对象都是 EventEmitter 的实例。常用的事件有:

  1. data - 当有数据可读时触发。
  2. end - 没有更多的数据可读时触发。
  3. error - 在接收和写入过程中发生错误时触发。
  4. finish - 所有数据已被写入到底层系统时触发。

从流中读取数据

var fs = require("fs");
var data = '';

// 创建可读流
var readerStream = fs.createReadStream('input.txt');

// 设置编码为 utf8。
readerStream.setEncoding('UTF8');

// 处理流事件 --> data, end, and error
readerStream.on('data', function(chunk) {
   data += chunk;
});

readerStream.on('end',function(){
   console.log(data);
});

readerStream.on('error', function(err){
   console.log(err.stack);
});

console.log("程序执行完毕");

写入流

var fs = require("fs");
var data = '菜鸟教程官网地址:www.runoob.com';

// 创建一个可以写入的流,写入到文件 output.txt 中
var writerStream = fs.createWriteStream('output.txt');

// 使用 utf8 编码写入数据
writerStream.write(data,'UTF8');

// 标记文件末尾
writerStream.end();

// 处理流事件 --> data, end, and error
writerStream.on('finish', function() {
    console.log("写入完成。");
});

writerStream.on('error', function(err){
   console.log(err.stack);
});

console.log("程序执行完毕");

管道流,提供了一个输出流到输入流的机制。通常我们用于从一个流中获取数据并将数据传递到另外一个流中,实现了大文件的复制过程。

var fs = require("fs");

// 创建一个可读流
var readerStream = fs.createReadStream('input.txt');

// 创建一个可写流
var writerStream = fs.createWriteStream('output.txt');

// 管道读写操作
// 读取 input.txt 文件内容,并将内容写入到 output.txt 文件中
readerStream.pipe(writerStream);

console.log("程序执行完毕");

链式流,通过连接输出流到另外一个流并创建多个对个流操作链的机制。链式流一般用于管道操作。用管道和链式来压缩和解压文件。

压缩文件
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');
}


// 调用方式
var hello = require('./hello');
hello.world();

模块接口

//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'); 
hello = new Hello(); 
hello.setName('BYVoid'); 
hello.sayHello(); 

模块接口的唯一变化是使用 module.exports = Hello 代替了exports.world = function(){}。 在外部引用该模块时,其接口对象就是要输出的 Hello 对象本身,而不是原先的 exports。

函数

一个函数可以作为另一个函数的参数

function say(word) {
  console.log(word);
}

function execute(someFunction, value) {
  someFunction(value);
}

execute(say, "Hello");

匿名函数

function execute(someFunction, value) {
  someFunction(value);
}

execute(function(word){ console.log(word) }, "Hello");

HTTP服务器

var http = require("http");

http.createServer(function(request, response) {
  response.writeHead(200, {"Content-Type": "text/plain"});
  response.write("Hello World");
  response.end();
}).listen(8888);

//或

var http = require("http");

function onRequest(request, response) {
  response.writeHead(200, {"Content-Type": "text/plain"});
  response.write("Hello World");
  response.end();
}

http.createServer(onRequest).listen(8888);

路由

router.js

function route(pathname) {
  console.log("About to route a request for " + pathname);
}

exports.route = route;

server.js

var http = require("http");
var url = require("url");

function start(route) {
  function onRequest(request, response) {
    var pathname = url.parse(request.url).pathname;  
    console.log("Request for " + pathname + " received.");

    route(pathname);

    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;

index.js

var server = require("./server");
var router = require("./router");

server.start(router.route);

推荐阅读更多精彩内容

  • Node基本 node的最大特性莫过于基于事件驱动的非阻塞I/O模型。 node通过事件驱动的方式处理请求,无须为...
    AkaTBS阅读 1,283评论 0 11
  • https://nodejs.org/api/documentation.html 工具模块 Assert 测试 ...
    KeKeMars阅读 4,368评论 0 6
  • 流是Node中最重要的组件和模式之一。在社区里有一句格言说:让一切事务流动起来。这已经足够来描述在Node中流...
    宫若石阅读 153评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 105,260评论 12 126
  • 嗯,我奔三了 谢谢今天我桐宝和佳艺宝宝带我吃到想吐的火锅鸡 谢谢我楚迎宝宝晚上的炸鸡和学姐的啤酒 谢谢我小丹的蛋糕...
    甘汝月阅读 40评论 3 1