前言: 本篇是我在阅读 nodejs 高级编程时写的阅读笔记, 如有出入, 不吝评论区赐教~
本篇涉及以下主题
node 简单介绍
事件驱动编程
模块化
缓冲区处理
Node 简单介绍
直接用官方的那句话:
Node.js 是一种建立在 Google Chrome's V8 引擎上的 non-blocking(非阻塞),event-driven(基于事件的)I/O 平台
Node.js 平台使用的开发语言是 JavaScript, 平台提供了操作系统底层的 API, 可以用来做后台开发
事件驱动编程
定义: 事件驱动编程是指程序的执行流程取决于事件的编程风格, 事件由事件处理程序或者事件回调函数进行处理. 当某些重要的事件发生时, 就会调用事件回调函数
Node 是作为一个非阻塞 I/O 服务平台设计的, 所以基于它构建的所有应用程序都是非阻塞的, 因为 JS 是天然轻量级, 所以 NODE 的构建基础很纯净
模块化
简单介绍完前面几个概念的东西, 我们在看看一些更贴近实际应用场景的, 如今模块化开发已经不是什么新鲜的问题了
在 node 中实现模块化有以下几种方式:
系统模块
第三方模块
文件模块
模块的加载和导出方式
语法:
require('module_name') 加载
module.exports 导出 也可以给 exports 对象加属性和方法
系统模块加载
- const http = require('http');
- // 使用该模块
- const server = http.createServer((req,res)=>{
- res.write('hello nodejs');
- });
- server.listen(8080);
这就是 http 系统模块搭建的简单的服务器, 服务器监听 8080 端口;
第三方模块
第三方模块也叫文件模块, 第三方模块和文件模块又有区别
1. 它可以是通过 npm 包管理工具安装的第三方模块 比如 mysql 这样的模块
使用的时候像核心模块那样 require('mysql')
2. 它允许是自定义模块
怎么理解? 当我们这样写的时候比如: const md = require('test'); 首先它会先去提供的核心模块中找 (node 文档中的一些核心模块), 找不到它会去 node_modules 文件夹下找举个例子:
- //index.js
- const test = require('test');
- console.log(test.a); // 'test'
- //node_modules test.js
- module.exports = {
- a: 'test'
- }
拓展
有时候我们看的第三方模块并不是一个文件而是文件夹
补充一点: 如果在查找的过程中没有找到例如 test.js 文件它会先当成是
test 文件夹, 当成是文件夹加载
然后问题又来了, 它会先找谁?
1. 在 node 中它会默认先找 index.js (在没指名入口文件时)
2. 如果该文件夹下 package.json 的 main 字段制定入口文件时, 按指定入口文件来
我们改造上边的例子
- //index.js
- const test = require('test');
- console.log(test.add(1,2)); // 3
- // node_modules/test/ main.js
- // 加入我这里的字段是 "main": "main.js", 如果没有会默认是 index.js
- module.exports.add = function(a,b) {
- return a+b;
- }
通过上边的例子我们在理解文件模块就很简单了
文件模块
在 node 中一切都是 js 文件, 所以一个 js 文件就可以看做是一个模块, 所以它有很好的伸缩性
补充: 在加载模块时, 默认加载. js 文件,(如果省略. js 的情况下, 也不一定是 js 文件, 也可以是. node 的二进制文件, 也可以是 json 等), 其次在加载模块时要使用绝对路径, 带'./' 和不带是有区别的
下面我们看下文件模块的加载方式
- //index.js
- const test = require('./test');
- console.log(test.a); // 'file'
- // test.js
- module.exports = {
- a: 'test'
- }
我们也可以自定义文件夹加载的模块 (内部定义好 package.json 就好)
我们还是拿上边的例子来修改
- //index.js
- const test = require('modules');
- console.log(test.add(1,2)); // 3
- // modules/test/ main.js
- // 加入我这里的字段是 "main": "main.js", 如果没有会默认是 index.js
- module.exports.add = function(a,b) {
- return a+b;
- }
缓冲区解读
我们主要聊聊以下几个方面的问题:
什么是缓冲区, 用来做啥
如何创建缓冲区
访问缓冲区
设置某个字节的数据
切分缓冲区
复制缓冲区
编码和解码二进制数据
好, 看起来内容有点多, 其实很简单, 我们切入正题
缓冲区的概念
我们都知道 JS 非常的善于处理字符串, 因此它并不善于处理二进制的数据. 在 js 中没有字节类型, 也没有结构类型, 也没有字节数组类型, 只有数值类型和字符串类型.
在服务器端, JS 可以很容易处理 http 这样的文本协议, 但是我们知道服务端不仅做这些, 可能会有数据库通信, 操作图像, 文件上传. 所以 JS 操作起来不是那么的容易, 浪费资源, 有很缓慢. 因此 Buffer 就出现了, 它作为 node 的一个核心模块, 专门来处理二进制数据.
要了解的 buffer 特点
Buffer 伪类的数据占用并不是分配在 JS 的 VM 内存堆中, 也就是说 Buffer 对象不会被 JS 的垃圾收集算法处理, 它占据的是一个不会被修改的永久内存地址, 这也避免了因缓冲区内容的内存复制而导致的 CPU 浪费.
创建缓冲区
缓冲区的创建方法很简单, 我们看一个例子:
- //1. utf-8
- const buf = new Buffer('hello world'); // 默认的编码方式
- //2. 指定编码方式
- const buf1 = new Buffer('8b76fde713ce','base64');
- //3. 创建指定长度的缓冲区
- const buf2 = new Buffer(1024);// 创建 1024 字节的缓冲区
- console.log(buf); //<Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>
访问缓冲区和相关操作
- // 访问缓冲区
- console.log(buf[2]); //buf 上第 2 个字节 ->108
- // 初始化缓冲区中的数据并非 0 而是一些随机值 (书上)
- console.log(buf2[1]); // 自己亲测的时候是 0 可能是我 node 版本的原因
- // 设置某个字节上的数据
- buf2[1] = 125;
- console.log(buf2[1]); // 125
- // 获取长度
- console.log(buf.length); // 11
- // 轶代缓冲区内容
- const buf3 = new Buffer(100);
- for(var i =0;i<buf3.length;i++) {
- buf3[i] = i;
- }
切分缓冲区
- // 切分缓冲区
- const buf4 = new Buffer('nihao node js');
- const smallerBuf = buf4.slice(8,12);
- console.log(smallerBuf.toString()); //de j
需要知道的几点:
1. 没有分配新的内存, 没有进行任何复制
2. 修改父缓冲区数据会影响到子缓冲区数据
3. 其实是创建了子缓冲区, 父缓冲区操作结束后依然继续被保留, 不能被垃圾回 收器回收, 会导致内存泄漏
4. 可以用 copy 方法代替
复制缓冲区
- // 复制缓冲区
- const buf5 = new Buffer(11);
- buf4.copy(buf5,0,8,19);
- console.log(buf5.toString()); //de js
解码和编码
- // 解码
- //1. 解析成 utf8 字符串
- console.log(buf3.toString());
- //2. 将 uft8 字符串解析成 base64 格式的
- console.log(smallerBuf.toString('base64')); //ZGUgag==
关于 node 的安装教程, 本篇没有详细提到, 网上有很多这样的教程, 就不说明了~
本篇阅读笔记就写到这里了, 后续还会更新~~
文章原创: 转载需联系作者
来源: http://www.jianshu.com/p/86af37075e41