Node 核心API基础

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

第三章 加载模块

本章提要

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

问题:

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

Node解决

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

3.1 理解Node如何加载模块

文件路径 + 名称

核心模块会预先加载

NPM安装模块

  1. var module = require('module_name');

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

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

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

3.2 导出模块

CommonJS模块系统

文件共享对象,函数.

模块和文件一一对应。

  1. function Circle(x,y,r){
  2. function r_squared(){
  3. return Math.pow(r,2);
  4. }
  5. function area(){
  6. return Math.PI * r_squared();
  7. }
  8. return {
  9. area : area
  10. }
  11. }
  12. module.exports = Circle;

module.exports

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

模块代码

  1. function printA(){
  2. console.log('A');
  3. }
  4. function printB(){
  5. console.log('B');
  6. }
  7. function printC(){
  8. console.log('C');
  9. }
  10. module.exports.printA = printA;
  11. module.exports.printB = printB;
  12. module.exports.pi = Math.PI;

引用模块

  1. var myModule2 = require('./myModule2');
  2. myModule2.printA();
  3. myModule2.printB();
  4. console.log(myModule2.pi);

3.3 加载模块

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

3.3.1 加载核心模块

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

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

  1. require(fs)

3.3.2 加载文件模块

提供绝对路径 或相对路径

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

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

可以省略.js的扩展名

3.3.3 加载文件夹模块

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

查找包定义,package.json

包不存在就会找 index.js

3.3.4 从node_modules 文件夹加载

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

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

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

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

推荐还是让NPM来管理

3.3.4 缓存模块

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

  1. console.log('module my_module initializing...');
  2. module.exports = function (){
  3. console.log('Hi!');
  4. }
  5. console.log('my_module initialized.');

然后加载

  1. 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 创建缓冲区

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

编码

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

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

  1. var buf = new Buffer(1024);

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

查看某个字节

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

注意

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

4.3 切分缓冲区

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

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

注意

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

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

4.4 赋值缓冲区

  1. var buffer = new Buffer('this is the content of my buffer');
  2. var smallerBuffer = buffer.slice(8,19);
  3. console.log(smallerBuffer.toString());
  4. var buf1 = new Buffer('this is the content of my buffer');
  5. var buf2 = new Buffer(11);
  6. var targetStart = 0;
  7. var sourceStart = 8;
  8. var sourceEnd = 19;
  9. buf1.copy(buf2, targetStart , sourceStart , sourceEnd);
  10. console.log(buf2.toString());

** 4.5 缓冲区解码**

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

打印

bXkgc3RyaW5n

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



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

发射事件

类似于发布/订阅模式。

5.1 理解标准回调模式

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

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

  1. var fs = require('fs');
  2. fs.readFile('/etc/passwd',function(err,fileContent){
  3. if(err){
  4. throw err;
  5. }
  6. console.info('file content',fileContent.toString());
  7. });

5.2 理解事件发射器模式

缺点

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

这样工作就不太好了。

事件发射器

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

负责监听特定类型的事件

  1. var req = http.request(options,function(response){
  2. response.on("data",function(data){
  3. console.log("some data",data);
  4. });
  5. response.on("end",function(){
  6. console.log("response ended");
  7. });
  8. });

PS

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

5.3 理解事件类型

事件类型

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

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

error事件

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

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

5.4 应用事件发生器API

方法

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

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

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

分析

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

可以使用on代替:

  1. readStream.on("data",receiveData);

PS:

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

5.4.2 绑定多个事件监听器

  1. readStream.on("data",function(data){
  2. console.log('I have data');
  3. });
  4. readStream.on("data",function(data){
  5. console.log('I have data 2');
  6. });

PS:

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

5.4.3 .removeListener 删除

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

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

.removeAllListeners

5.5 创建事件发射器

5.5.1 从Node事件发射器继承

  1. var util = require('util');
  2. var events = require('events').EventEmitter;
  3. var MyClass = function(){
  4. //原型链
  5. util.inherits(MyClass, EventEmitter);
  6. }

发射事件

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

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



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

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

6.1 使用 setTimeout推迟

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

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

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

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

有时候不需要立刻执行。

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

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

  1. process.nextTick(function(){
  2. my_expensive_conmputation_function();
  3. });

6.5 阻塞队列事件循环

单线程事件循环。

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

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

[阻塞]

  1. process.nextTick(function nextTick1(){
  2. var a = 0;
  3. while(true){
  4. a++;
  5. }
  6. });
  7. process.nextTick(function nextTick2(){
  8. console.log("2.....");
  9. });
  10. setTimeout(function timeout(){
  11. console.log(1);
  12. },1000);

6.6 推出事件循环

释放事件

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

  1. var inteval = 1000;
  2. setInterval(function(){
  3. my_async_function(function(){
  4. console.log('finished...!');
  5. });
  6. });

《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. pythond的icmp广播报获取局域网主机IP

    icmp广播报获取局域网四川特产IP from scapy.all import *import randomimport threading def scan(sip,dip): pkt = Eth ...

  2. python 获取list的下标

    print(your_list.index('your_item')) #your_list为列表名称 your_item为需要修该的数据

  3. L3-021 神坛(极角排序求三角形最小面积)

    在古老的迈瑞城,巍然屹立着 n 块神石.长老们商议,选取 3 块神石围成一个神坛.因为神坛的能量强度与它的面积成反比,因此神坛的面积越小越好.特殊地,如果有两块神石坐标相同,或者三块神石共线,神坛的面 ...

  4. redis缓存与数据库一致性问题

    一般来说,如果允许缓存可以稍微的跟数据库偶尔有不一致的情况,也就是说如果你的系统不是严格要求 “缓存+数据库” 必须保持一致性的话,最好不要做这个方案,即:读请求和写请求串行化,串到一个内存队列里去. ...

  5. 记忆化搜索 P1464 Function

    题目描述 对于一个递归函数w(a,b,c) 如果a≤0 or b≤0 or c≤0就返回值1. 如果a>20 or b>20 or c>20就返回w(20,20,20) 如果a< ...

  6. windows下的mongodb安装与配置

    一.下载mongodb安装文件 https://www.mongodb.com/download-center/community 选择zip压缩包方式,如:mongodb-win32-x86_64- ...

  7. 小程序解析html(使用wxParse)

    正好遇到一个数据里面是html格式的数据,小程序不支持,网上找到这个做下记录,下面是我下好的wxParse文件目录 我的文件夹放的和pages同级 1.首先引入样式@import "/wxP ...

  8. Oracle 12导出、导入数据

    Precondition: complete the work described in Oracle 12 创建新的数据库实例.用户 1. export data under user " ...

  9. hadoop_随笔二_参数

    1) dfs.datanode.handler.count : datanode上用于处理RPC的线程数.默认为3,较大集群,可适当调大些,比如8.需要注意的是,每添加一个线程,需要的内存增加. 2) ...

  10. Maven中阿里云私服配置

    在国内maven仓库连接速度太慢 ,虽然对于很多互联网企业和大中型软件公司,建个镜像是分分钟的事.但对于个人开发者确实是个问题.解决办法可以用阿里云的MAVEN私服.有两种方法: 1.在$MAVEN_ ...