简单的说 Node.js 就是运行在服务端的 JavaScript。它的优势是基于Google的V8引擎(执行速度非常快、性能非常好、社区活跃),更具诱惑力的是采用node+mongodb开发中小型网站速度更快(据说成本更低)。

目录

1.1. Node简介

1.2. 下载安装

1.3. 模块机制

1.4. 异步I/O

1.5. 异步编程

1.6. 核心API

1.6.1.  Event

1.6.2.  HTTP

1.6.3.  I/O

1.7. 全局对象&全局变量

1.8. util模块

1.9. assert断言

1.10.  npm

1.10.1.  package.json

1.10.2.  命令

1.10.3.  远程镜像

1.11.  Cluster模块

1.12.  PM2模块


1.1. Node简介

nodejs学习笔记》入门级教程_nodejs

1.2. 下载安装

https://nodejs.org/zh-cn/download/releases/

1.3. 模块机制

nodejs学习笔记》入门级教程_事件循环_02

1.4. 异步I/O

nodejs学习笔记》入门级教程_pm2_03

1.5. 异步编程

 

nodejs学习笔记》入门级教程_HTTP_04

1.6. 核心API

1.6.1.  Event

events是Node.js最重要的模版,原因是Node.js本身架构就是事件式的,而它提供了唯一的接口。所以开成Node.js事件编程的基石。events模块不仅用于用户代码与Node.js下层事件循环的交互。还几乎被所有的模块依赖。

events模块只提供了一个对象(events.EventEmitter)。EventEmitter的核心就是事件发射事件监听器功能的封装。EventEmitter的每个事件由一个事件或若干个参数组成,事件名是一个字符串,通常表达一定的语义。对于每个事件,EventEmitter支持若干个事件监听器。当事件发射时,注册到这个事件的事件监听器被依次调用,事件参数作为回调函数参数传递。

常用API的方法:

(1)EventEmitter.on(event,listener)为指定事件注册一个监听器,接受一个字符串event和一个回调函数listener

(2)EventEmitter.emit(event,[arg1],[arg2]....)发射event事件,传递若干可选参数到事件监听器的参数表

(3)EventEmitter.once(event,listener) 为指定事件注册一个单次监听器,即监听器最多只会触发一次,触发后立刻解除该监听器。

(4)EventEmitter.removeListener(event,listener)移除指定事件的某个监听器,listener必须是该事件已经注册过的监听器。

(5)EventEmitter.removeAllListeners([event])移除所有事件的所有监听器,如果指定event,则移除指定事件的所有监听器。

事件

1.普通事件的使用

//声明事件对象`
var EventEmitter=require('events').EventEmitter;
var event=newEventEmitter();
//注册事件
event.on('some_event', function() {
    console.log('这是一个自定义的事件');
});

//触发事件
setTimeout(function() {
      event.emit('some_event');
}, 1000);
console.log("event...")

2.Node.js的事件循环机制

(1)Node.js在什么时候进入事件循环呢?

Node.js程序是由事件循环开始,到事件循环结束,所有的逻辑都是事件的回调函数。

(2)如何使用自定义事件呢?

事件的回调函数在执行的过程中,可能会发出IO请求或直接发射(emit)事件,执行完毕后再返回事件循环。

回调函数

异步式读取文件:

var fs=require('fs');
fs.readFile('file.txt', 'utf-8', function(err, data) {
    if (err) {
        console.log(err)
    } else {
        console.log(data)
    }
});
console.log('end.')

同步式读取文件:

var fs=require('fs');
var data=fs.readFileSync('file.txt', 'utf-8');
console.log(data)
console.log('end.')

分析:

调用时所做的工作知识将异步式IO请求发送给了操作系统,然后立即返回并执行后面的语句,执行完以后进入事件循环监听事件,当fs接受到IO请求完成的事件时。事件循环会主动调用回调函数完成后续工作。同步则是阻塞等待完成后,继续执行。

1.6.2.  HTTP

Node.js 的核心功能之一就是作为Web 服务器,这是这个系统的一个重要部分,所以当 Ryan Dahl 发起此项目时,他为 V8 重写了 HTTP 模块,使其能够非阻塞运行。虽然最开始的 HTTP 实现已经蜕变了许多,API 和内部实现不断升级,但核心操作还是保持不变的。Node 实现的 HTTP 模块是非阻塞的,且速度很快,其中许多代码已经从 C 迁移到了 JavaScript。HTTP 使用的模式在 Node 里很常见。父工厂类提供了很容易创建新服务器的方法。http.createServer() 方法为我们提供了构建新的 HTTPServer 类的实例。我们可以为新的类定义 Node 接受到 HTTP 请求时的操作。HTTP 模块及其他 Node 模块还有一些共性的地方,比如 Server 类能够触发的事件,还有传给回调函数的数据

结构。了解这 3 种类型有助于你更好地使用 HTTP 模块。

Http服务器

var http=require('http');
var server=http.createServer();
var handleReq=function(req, res) {
        res.writeHead(200, {});
        res.end('hello world');
};
server.on('request', handleReq);
server.listen(8125);
console.warn("localhost is running")

Http客户端

如果你想向远程服务器发起 HTTP 连接,Node 也是很好的选择。Node 在许多情下都很适合使用,如使用 Web  service,连接到文档数据库,或是抓取网页。你可使用同样的 http 模块来发起 HTTP 请求,但应该使用 http.ClientRequest 类该类有两个工厂方法:一个通用的方法和一个便捷的方法。

var http=require('http');
var opts= {
  host:'www.baidu.com',
  port:80,
  path:'/',
  method:'GET'
};
var req=http.request(opts, function(res) {
  console.log(res);
  res.on('data', function(data) {
    console.log(data);
  });
});
req.end()

URL

var URL=require('url');
var myUrl="http://www.nodejs.org/some/url/?with=query";
console.log(myUrl)
var parsedUrl=URL.parse(myUrl);
console.log(parsedUrl)

querystring

querystring 模块是用来处理 query 字符串的简单辅助模块。上一小节已经讨论过,query 字符串是在 URL 尾部编码过的参数。但是如果只是把它当做 JavaScript字符串来使用时,处理这些参数未免很烦琐。querystring 模块提供了从 query字符串中轻松提取对象的方法。它的主要功能有 parse 和 decode,还包括一些内部辅助函数,如 escape、unescape、unescapeBuffer、encode 和 stringify。如果你有一个 query 字符串,你可以使用 parse 来把它变成一个对象。

var qs=require('querystring');
console.log(qs.parse('a=1&b=2&c=d'))

1.6.3.  I/O

数据流

可读的数据流API是一组方法和事件,提供了数据源在发送时访问数据块的功能。

基本上,可读数据流是与触发 data 事件相关的

var fs=require('fs');
var filehandle=fs.readFile('file.txt', function(err, data) {
  console.log(data)
 });

有时候我们需要等待完整的数据都可用后再进行操作,在这种情况下就会用到数据池模式(spooling  pattern)。我们知道重点是不要让 Node 的事件循环阻塞,所以即使不想在接收到所有数据之前进行下一步处理,也不希望堵塞事件循环。在这种情况下,我们使用数据流来读取数据,但只有在接收到足够的内容后才使用这些数据。

var spool="";
stream.on('data', function(data) {
        spool+=data;
});
stream.on('end', function() {
        console.log(spool);
});

文件系统

文件系统模块显然非常有用,因为你需要它来访问磁盘上的文件。它几乎模仿了文

件 I/O 的 POSIX 风格,示例:读取并删除文件——但这是错误的(它是异步的

var fs=require('fs');
fs.readFile('warandpeace.txt', function(e, data) {
        console.log('War and Peace: '+data);
});
fs.unlink('warandpeace.txt');

//正确的是:
var fs=require('fs');
fs.readFile('warandpeace.txt', function(e, data) {
        console.log('War and Peace: '+data);
        fs.unlink('warandpeace.txt');
});

Buffer

浏览器需要JavaScript 来进行许多操作,但并不包括处理二进制数据。虽然说JavaScript 支持字节位操作,但它并没有二进制数据的原生表现形式。Node 带来了 Buffer 类,为你操作二进制数据弥补了短板。Buffer 是 V8 引擎上的扩展,这意味着它有其固有的一些限制。Buffer 实际上是对内存的直接分配,这意味着这多少受制于你在低级计算机语言方面的经验。

支持的编码类型:ASCII、UTF-8(默认)、UTF-16、Base64、Binary、Hex

//不支持的编码格式
console.log(Buffer.isEncoding('gbk'))
//字符串转Buffer
var bf=newBuffer('foobarbaz')
console.log(bf)
//Buffer转字符串
var foo=bf.toString()
console.log(foo)

console.log

这个简单的 console.log 命令借用了 Firefox 中 Firebug 调试器的概念,让你可以

轻松把输出打印到标准输出(stdout)

1.7. 全局对象&全局变量

在JavaScript中,通常window是全局对象,而Node.js的全局对象是global,所有全局变量都是global对象的属性,如:console、process等。

全局变量

global最根本的作用是作为全局变量的宿主,满足以下条件成为全局变量:

1.在最外层定义的变量

2.全局对象的属性

3.隐式定义的变量(未定义直接赋值的变量)

在Node.js中不可能在最外层定义变量,因为所有用户代码都是属于当前模块的,而模块本身不是最外层上下文。

process

它用于描述当前Node.js进程状态的对象。提供了一个与操作系统的简单接口,通常写本地命令行程序的时候,会用到它。

1.process.argv是命令行参数数组,第一个元素是node,第二个元素是脚本文件名,第三个元素开始每个元素是一个运行参数。

2.process.stdout是标准输出流,通常我们使用的console.log() 其底层是用process.stdout.write();实现。

3.prcess.stdin是标准输入流,初始时它是被暂停的。要想从标准输入流读取数据,必须恢复流,并手动编写流的事件相应函数。

4.process.nextTick(callback)的功能是为事件循环设置一项任务。Node.js会在下次事件循环调响应时调用callback,ode.js适合IO密集型的应用,而不是计算密集型的应用。process.nextTick()提供了一个这样工具,可以把复杂的工作拆散,编较小的事件程一个。

function doSomething(args, callback) {
     somethingComplited(args);
     callback();
}
doSomething('12345', function onEnd() {
         compute();
})

//如果假设compute()和somethingComplited()是两个较为耗时的函数。 以上的程序在调用doSomething时会先执行somethingComplited(args), 然后立即调用回调函数,在onEnd()中又会执行compute(),改写为:
function doSomething(args, callback) {
     somethingComplited(args);
     process.nextTick(callback);
}

使用process.nextTick() 后,改写后的程序会把上面耗时的操作拆分为两个事件,减少每个事件的执行时间,提高事件相应速度。

5.process还提供了process.pid、process.execPath、process.memoryUsage()等

1.8. util模块

util.log(string)

将 string 参数的内容加上当前时间戳,输出到 stdout 标准输出

require('util').log('Timestmaped message.');

输出: 14 Jun 16:02:06 - Timestmaped message.

util.inspect(object, showHidden=false, depth=2)

以字符串形式返回 object 对象的结构信息,这对程序调试非常有帮助

var util=require('util');
console.log(util.inspect(util, true, null));

util.inherits(constructor, superConstructor)

实现对象间原型继承的函数

var util=require("util");
var events=require("events");
function MyStream() {
    events.EventEmitter.call(this);
}
util.inherits(MyStream, events.EventEmitter);
MyStream.prototype.write=function(data) {
    this.emit("data", data);
}
var stream=newMyStream();
console.log(streaminstanceofevents.EventEmitter); // true 
console.log(MyStream.super_===events.EventEmitter); // true 
stream.on("data", function(data) {
    console.log('Received data: "'+data+'"');
})
stream.write("It works!"); // Received data: "It works!"

1.9. assert断言

断言(Assert)模块用于为应用编写单元测试,可以通过 require('assert')对该模块进行调用。

var assert=require('assert');
assert.equal(1, true, 'Truthy');
assert.notEqual(1, true, 'Truthy');

1.10.  npm

1.10.1. package.json

package.json位于模块的目录下,用于定义包的属性。我们可以看下 express 包位于 node_modules/express/package.json文件

Key

描述

name

- 包名。

version

- 包的版本号。

description

- 包的描述。

homepage

- 包的官网 url 。

author

- 包的作者姓名。

contributors

 - 包的其他贡献者姓名。

dependencies

 - 依赖包列表。如果依赖包没有安装,npm 会自动将依赖包安装在 node_module 目录下。

repository

- 包代码存放的地方的类型,可以是 git 或 svn,git 可在 Github 上。

main

- main 字段是一个模块ID,它是一个指向你程序的主要项目。就是说,如果你包的名字叫 express,然后用户安装它,然后require("express")。

keywords

- 关键字

 

 

1.10.2. 命令

命令行

描述

npm –v

显示版本

npm config list

查看配置

npm config set prefix "D:\Program\nodejs\node_global"

npm config set cache "D:\Program\nodejs\node_cache"

npm install express

 

安装或升级express(web框架模块)

代码中:var express = require('express');

-g全局安装

--save-dev 安装本地并保存到package.json中

npm install webpack@1.2.x 指定版本

npm ls

查看已安装的模块

-g 查看全局已安装的模块

npm uninstall express

卸载模块

npm update express

更新模块

npm search express

搜索模块

npm init

创建模块

npm publish

发布模块

npm cache clear

可以清空NPM本地缓存

npm unpublish <package>@<version>

撤销发布自己发布过的某个版本代码

1.10.3.  远程镜像

大家都知道国内直接使npm的官方镜像是非常慢的,

l  淘宝npm镜像

    搜索地址:http://npm.taobao.org/

   registry地址:http://registry.npm.taobao.org/

l  cnpmjs镜像

    搜索地址:http://cnpmjs.org/

   registry地址:http://r.cnpmjs.org/

配置npm的registry地址:

l  临时使用

npm --registry https://registry.npm.taobao.org installexpress

l  持久使用

npm config set registryhttps://registry.npm.taobao.org

npm config get registry // 配置后可通过下面方式来验证是否成功

npm info express // 或

当然你可以使用淘宝定制的cnpm (gzip 压缩支持) 命令行工具代替默认的 npm。

npm install -gcnpm --registry=https://registry.npm.taobao.org

cnpm install[name]

1.11.  Cluster模块

Node.js默认单进程运行,对于32位系统最高可以使用512MB内存,对于64位最高可以使用1GB内存。对于多核CPU的计算机来说,这样做效率很低,因为只有一个核在运行,其他核都在闲置。cluster模块就是为了解决这个问题而提出的。

cluster模块允许设立一个主进程和若干个worker进程,由主进程监控和协调worker进程的运行。worker之间采用进程间通信交换消息,cluster模块内置一个负载均衡器,采用Round-robin算法协调各个worker进程之间的负载。运行时,所有新建立的链接都由主进程完成,然后主进程再把TCP连接分配给指定的worker进程。

1.12.  PM2模块

PM2模块是cluster模块的一个包装层。它的作用是尽量将cluster模块抽象掉,让用户像使用单进程一样,部署多进程Node应用。

好了,掌握了这一篇我们可以了解下一篇《常用node组件》