Node 核心API基础

  • 第三章 加载模块
  • 第四章 应用缓冲区
  • 第五章 事件发射器模式简化事件绑定
  • 第六章 使用定时器制定函数执行计划

第三章 加载模块

本章提要

  • 加载模块
  • 创建模块
  • 使用node_modules文件夹

问题:

  • 全局名称空间,共享
  • 安全性问题、冲突、难以跟踪与解决。

Node解决

  • 使用了CommonJS模块标准。
  • 划分模块,根本没有全局作用域

3.1 理解Node如何加载模块

文件路径 + 名称

核心模块会预先加载

NPM安装模块

var module = require('module_name');

该对象表示模块对外暴露的 JavaScript API

它可以是一个函数,也可以是一个具有若干属性的对象,

属性可能是函数、数组,或者是其他类型。

3.2 导出模块

CommonJS模块系统

文件共享对象,函数.

模块和文件一一对应。

function Circle(x,y,r){
function r_squared(){
return Math.pow(r,2);
} function area(){
return Math.PI * r_squared();
} return {
area : area
}
} module.exports = Circle;

module.exports

  • 模块向需要它的脚本所导出的对象,可以是任意对象。

模块代码

function printA(){
console.log('A');
} function printB(){
console.log('B');
} function printC(){
console.log('C');
} module.exports.printA = printA;
module.exports.printB = printB;
module.exports.pi = Math.PI;

引用模块

var myModule2 = require('./myModule2');
myModule2.printA();
myModule2.printB();
console.log(myModule2.pi);

3.3 加载模块

require函数不会改变全局名称空间的状态,Node种根本没有全局名称空间的概念。

3.3.1 加载核心模块

核心模块,二进制形式发布的模块。

只能通过模块名,而不能通过文件路径。

require(fs)

3.3.2 加载文件模块

提供绝对路径 或相对路径

从文件系统加载非核心模块

var myModule = require ('/home/carvendy/my_modules/my');

可以省略.js的扩展名

3.3.3 加载文件夹模块

var myModule = require('./myModuleDir');

查找包定义,package.json

包不存在就会找 index.js

3.3.4 从node_modules 文件夹加载

如果一个模块既不是相对路径,也不是核心模块,

那么就会尝试在当前目录下的 node_modules文件中查找。

var myModule = require('myModule.js');

当前目录没有myModule.js,就会往上一级父目录查找,持续到达根目录。

推荐还是让NPM来管理

3.3.4 缓存模块

模块在首次加载时,会被缓存起来,这意味着能被解析为相同的文件名。

console.log('module my_module initializing...');
module.exports = function (){
console.log('Hi!');
}
console.log('my_module initialized.');

然后加载

var myModule = require('./my_module');

输出

module my_module initializing...

module my_module initialized.

加载两次效果一样

模块在初始化,可能会有副作用

总结

  • CommonJS模块系统取代,js默认全局名称空间
  • 避免是安全性问题和错误。
  • 使用require()加载模块
  • 还可以编写 JavaSript导出的模块API

第四章 应用缓冲区处理、编码和解码二进制数据



#### 本章提要
- 理解Node 中为何需要缓冲区
- 用字符串创建缓冲区
- 将缓冲区转换成字符串
- 在缓冲区中处理数据
- 切分和复制缓冲区

问题

  • js 善于处理字符串,但是它是被设计处理HTML,不擅长处理二进制数据。
  • js没有字节类型,没有结构化类型,甚至没有字节数组
  • 只有数值类型和字符串

Node 解决

  • 处理HTTP文本协议
  • 数据库通信、图像操作。
  • 前期,使用字符串处理二进制,性能底下。
  • 于是,引入了二进制缓冲区。(字节为计量单位)

补充

Buffer类的另一特别之处是数据占用的内存并不是分配JavaScript VM内存堆,这些对象不会被垃圾收集算法处理。

它会占据一个不会被修改的永久内存地址,这避免了因缓冲区内容的内存复制所造成的CPU浪费。

4.1 创建缓冲区

var buf = new Buffer('Hello World');//使用utf-8
var buf = new Buffer('8b76fdes713ce','base64');

编码

  • ascii, ASCII字符集
  • utf8, UTF-8
  • base64,Base64个可打印的ASCII字符

如果缓冲区没有具体内容初始化,那么可以指定容量大小创建,备用

var buf = new Buffer(1024);

4.2 在缓冲区中获取和设置数据

查看某个字节

var buf = new Buffer('my buffer content');
console.log(buf[10]);//-->99 (随机值)

注意

  • 设置一个大于255的数,将会用256对该数取模,赋值。
  • 设置256,实际上被赋值为0
  • 设置为100.7的小数,只会存储100
  • 如果尝试给超出缓冲区边界的位置赋值,那么将会失败告终。
var buf = new Buffer(100);
console.log(buf.length);

4.3 切分缓冲区

对于已经创建的缓冲区,也许需要提取一部分。

var buffer = new Buffer('this is the content of my buffer');
var smallerBuffer = buffer.slice(8,9);
console.log(smallerBuffer.toString());

注意

切缓冲区,并没有分配新的内存。只不过引用父缓冲区的起始和结束位置。

修改父,删除父,可能会有错误,或内存泄漏。

4.4 赋值缓冲区

var buffer = new Buffer('this is the content of my buffer');
var smallerBuffer = buffer.slice(8,19);
console.log(smallerBuffer.toString()); var buf1 = new Buffer('this is the content of my buffer');
var buf2 = new Buffer(11); var targetStart = 0;
var sourceStart = 8;
var sourceEnd = 19; buf1.copy(buf2, targetStart , sourceStart , sourceEnd);
console.log(buf2.toString());

** 4.5 缓冲区解码**

var buf = new Buffer('this is the content of my buffer');
var str = buf.toString('base64');

打印

bXkgc3RyaW5n

第五章 使用事件发射器模式简化事件绑定



#### 本章提要:
- 事件发射器模式简介
- 绑定和解绑事件监听器
- 创建自定义的事件发射器

发射事件

类似于发布/订阅模式。

5.1 理解标准回调模式

异步编程不使用函数返回值代表结束,而使用后继传递。

每个函数执行完毕后都会调用一个回调函数。

var fs =  require('fs');
fs.readFile('/etc/passwd',function(err,fileContent){
if(err){
throw err;
}
console.info('file content',fileContent.toString());
});

5.2 理解事件发射器模式

缺点

如果在函数执行过程中发生了很多事件,或者事件反复多次出现。

这样工作就不太好了。

事件发射器

看月发射事件的兑现,而事件监听器则是绑定到事件发射器上的代码,

负责监听特定类型的事件

var req = http.request(options,function(response){
response.on("data",function(data){
console.log("some data",data);
});
response.on("end",function(){
console.log("response ended");
});
});

PS

  • 当需要在请求操作完成智慧重新获取控制权看月使用CPS模式
  • 当事件可以发生多次时,就使用事件发射器模式

5.3 理解事件类型

事件类型

按照一般约定,事件类型都是由不包含开个的小写单词组成的。

无法通过编程判断发射了哪些类型的事件,API没有提供内省机制。

error事件

如果程序员选择不监听"error"事件,当事件发生是,事件发射器注意到它,并抛出未捕获异常。

var em = new (require('events').EventEmitter)();
em.emit('event1');//没有的事件
em.emit('error', new Error('My mistake'));// error马上打印堆栈

5.4 应用事件发生器API

方法

  • .addListener 和.on —— 添加事件监听
  • .once ——指定,并只邦定一个近被调用一次
  • .removeEventListener ——删除
  • .removeAllEventListener ——删除所有绑定的事件

5.4.1 使用.addListener或.on 绑回调函数

function receiveData(data){
console.info("got data from server");
}
readStream.addListener("data",receiveData);

分析

当有可用数据块时,文件可读流就会发射“data”事件

可以使用on代替:

readStream.on("data",receiveData);

PS:

data事件可能会传递数据缓冲区,error事件可能会传递一个错误对象,而流“end”事件则不向事件监听器传递任何参数。

5.4.2 绑定多个事件监听器

readStream.on("data",function(data){
console.log('I have data');
});
readStream.on("data",function(data){
console.log('I have data 2');
});

PS:

  • 有注册顺序
  • 监听器没有执行,可能是前面还有一个监听器
  • 异常,可能会永远不会被执行。
  • 第一个事件抛错误了,第二个监听器就不会执行。

5.4.3 .removeListener 删除

5.4.4. .once() 最多执行一次

var event = require('events').EventEmitter;
EventEmitter.prototype.once = function (type,callbak){
var that = this;
this.on(type,function listener(){
that.removeListener(type,listener);
callback.apply(that,arguments);//参数原封不动传递,再调回调函数
});
}

.removeAllListeners

5.5 创建事件发射器

5.5.1 从Node事件发射器继承

var util = require('util');
var events = require('events').EventEmitter;
var MyClass = function(){
//原型链
util.inherits(MyClass, EventEmitter);
}

发射事件

MyClass.prototype.someMethod = function (){
this.emit("custom event","argument 1","argument 2");
} // 触发
var myClazz = new MyClass();
myClazz.on('custom event',function(str1,str2){
console.log("one:%s,two:%s",str1,str2);
}); myClazz.someMethod();

第六章 定时器指定函数执行计划



#### 本章提要
- 推迟函数的执行
- 取消执行计划
- 指定函数的周期行执行计划
- 将函数执行推迟到下一轮事件循环

Node全面实现一组函数,它们被用来再服务端辅助不通进程进行后期限或者推迟执行。

6.1 使用 setTimeout推迟

var timeout_ms = 2000;
var timeout = setTimeout(functino({
console.log('do sime');
}),timeout_ms);
clearTimeout(timeout);//取消函数计划

6.2 指定和取消函数的重复执行计划

var period = 1000;
setInterval(function(){
console.log("tick");
},period);

6.4 使用process.nextTick将函数执行推迟到下一个事件循环

有时候不需要立刻执行。

事件循环在一个处理事件队列的循环运行,事件循环每执行一次就被称为一个"tick"

process.nextTick 比激活超时队列块。

process.nextTick(function(){
my_expensive_conmputation_function();
});

6.5 阻塞队列事件循环

单线程事件循环。

运行时调用相关回调函数来处理队列的下个事件。

特殊情况,如果某个回调占用事件长,整个服务就会非常缓慢。

[阻塞]

process.nextTick(function nextTick1(){
var a = 0;
while(true){
a++;
}
}); process.nextTick(function nextTick2(){
console.log("2.....");
}); setTimeout(function timeout(){
console.log(1);
},1000);

6.6 推出事件循环

释放事件

6.7 使用 setTimeout 代替setInteval 前置函数串行

var inteval = 1000;
setInterval(function(){
my_async_function(function(){
console.log('finished...!');
});
});

《Node.js高级编程》之Node 核心API基础的更多相关文章

  1. Node.js高级编程读书笔记Outline

    Motivation 世俗一把,看看前端的JavaScript究竟能做什么. 顺便检验一下自己的学习能力. Audience 想看偏后台的Java程序员关于前端JavaScript的认识的职业前端工程 ...

  2. 《Node.js 高级编程》简介与第二章笔记

    <Node.js 高级编程> 作者简介 Pedro Teixerra 高产,开源项目程序员 Node 社区活跃成员,Node公司的创始人之一. 10岁开始编程,Visual Basic.C ...

  3. Node.js高级编程读书笔记 - 1 基本概念

    Outline 1 概述和安装 1.1 安装Node 1.2 Node简介 2 Node核心API基础 2.1 加载模块 2.2 应用缓冲区处理.编码和解码二进制数据 2.3 使用时间发射器模式简化事 ...

  4. Node.js高级编程读书笔记 - 6 应用程序构建和调试 - Never

    Explanation 现阶段console.log(...),util.inspect(...), JSON.stringify(...)在控制台输出已经够用了[2015/07/19]. 单元测试隶 ...

  5. Node.js高级编程读书笔记 - 5 数据库 - Never

    Outline 6 连接数据库 6.1 使用node-mysql连接MySQL数据库 6.2 使用Nano连接CouchDB数据库 6.3 使用Mongoose连接MongoDB数据库 6 连接数据库 ...

  6. Node.js高级编程读书笔记 - 2 文件和进程处理

    Outline 3 文件.进程.流和网络 3.1 查询和读写文件 3.2 创建和控制外部进程 3.3 读写数据流 3 文件.进程.流和网络 3.1 查询和读写文件 path 从Node 0.8起,pa ...

  7. Node.js高级编程读书笔记 - 4 构建Web应用程序

    Outline 5 构建Web应用程序 5.1 构建和使用HTTP中间件 5.2 用Express.js创建Web应用程序 5.3 使用Socket.IO创建通用的实时Web应用程序 5 构建Web应 ...

  8. Node.js高级编程读书笔记 - 3 网络编程

    Outline 3.4 构建TCP服务器 3.5 构建HTTP服务器 3.6 构建TCP客户端 3.7 创建HTTP请求 3.8 使用UDP 3.9 用TLS/SSL保证服务器的安全性 3.10 用H ...

  9. 深入理解node.js异步编程:基础篇

    ###[本文是基础内容,大神请绕道,才疏学浅,难免纰漏,请各位轻喷] ##1. 概述 目前开源社区最火热的技术当属Node.js莫属了,作为使用Javascript为主要开发语言的服务器端编程技术和平 ...

随机推荐

  1. 【相关网站 - 02】- Java 好文博客

    一.源码分析博客 还有这种操作?浅析为什么要看源码 你觉得什么才是 Java 的基础知识? 1. JDK 2. Mybatis 3. Spring 4. Sring Boot 5. Spring Cl ...

  2. 什么是HTML?

    html是很多人编程的入门领域.作为初学者,不管你是在哪里学的,学校,视频教程,网络教程等等……它们都会告诉你HTML即:超文本标记语言(Hyper Text Markup Language).但第一 ...

  3. TZOJ 2289 Help Bob(状压DP)

    描述 Bob loves Pizza but is always out of money. One day he reads in the newspapers that his favorite ...

  4. java_25.1字节转为字符OutputStreamWriter

    public class Demo { public static void main(String[] args){ try { FileOutputStream fos = new FileOut ...

  5. java集合类,HashMap,ArrayList

    集合类 Collection LinkedList.ArrayList.HashSet是非线程安全的, Vector是线程安全的; ArrayXxx:底层数据结构是数组,连续存放,所以查询快,增删慢. ...

  6. AutoMapper 忽略某个字段

    以前要在定义中忽略 Mapper.CreateMap<Source, Destination>() .ForMember(dest => dest.SomeValuefff, opt ...

  7. Qt5.12.2开发Android环境搭建

    Qt-Android开发环境概要qt-opensource-windows-x86-5.12.2----armv7jdk-8u201-windows-x64android-ndk-r18b-windo ...

  8. hanjiaqi

    2017*1501:我是韩佳琦:我的爱好是睡觉: 我的码云个人主页是:https://gitee.com/projects/new 我的第一个项目地址是:https://gitee.com/hanji ...

  9. Js有一个已经排好序的数组。现输入一个数,要求按原来的规律将它插入数组中。

    <!DOCTYPE html> <title>Title</title> <script> var arr = [1,2,3,4,11]; var s ...

  10. shell速查

    Shell是一种脚本语言,那么,就必须有解释器来执行这些脚本,常见的脚本解释器有: bash:是Linux标准默认的shell.bash由Brian Fox和Chet Ramey共同完成,是Bourn ...