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);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • Node基本 node的最大特性莫过于基于事件驱动的非阻塞I/O模型。 node通过事件驱动的方式处理请求,无须为...
    AkaTBS阅读 2,094评论 0 11
  • https://nodejs.org/api/documentation.html 工具模块 Assert 测试 ...
    KeKeMars阅读 6,221评论 0 6
  • 流是Node中最重要的组件和模式之一。在社区里有一句格言说:让一切事务流动起来。这已经足够来描述在Node中流...
    宫若石阅读 500评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,099评论 18 139
  • 30岁前,你不辞职,此生还指望做什么? 老删在深圳海边开了一家客栈,本是一栋平凡无奇的三层楼民宿,说白了就是村儿里...
    海欧亭亭阅读 36,482评论 60 148