node.js事件循环

node.js单进程,单线程的程序
每一个api都支持回调
所有的事件机制都是设计模式中的

一共是23种设计模式
http://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/observer.html
一个对象发生改变的时候,将自动通知其他对象,其他对象将相应的做出反应。发生改变的对象为观察目标,被通知的对象为观察者。一个观察目标可以对应多个观察者,而这些观察者之间没有任何联系,可以根据需要增加观察者,使得系统更加容易扩展,依赖关系为一对多,又被称为模型-视图模式

事件驱动程序

web server接收到请求,将其关闭,进行处理,然后接着服务下一个web请求。
当请求完成以后,放回处理队列,当到达队列开头的时候,将其结果返回给用户
即非阻塞式I/O 事件驱动I/O
会有一个主循环来监听事件,当检测到事件以后,触发回调函数

代码

PS C:\Users\mingm\Desktop\test> node main.js
连接成功
数据接收成功
程序执行完毕
PS C:\Users\mingm\Desktop\test>
// 引入一个 events 模块
var events = require('events');
// 创建 eventEmitter对象
var eventEmitter = new events.EventEmitter();// 创建connection事件的处理程序
var connectHandLer = function connected() {console.log('连接成功');// 触发 data_received 事件eventEmitter.emit('data_received');
};// 绑定cinnection事件处理程序
eventEmitter.on('connection', connectHandLer);// 绑定data_received事件,并完成处理程序的书写
eventEmitter.on('data_received',function() {console.log('数据接收成功');});// 触发 connection 事件
eventEmitter.emit('connection');console.log('程序执行完毕');

程序的执行过程,先完成各种绑定,触发connection事件以后,寻找绑定的处理程序,为connected(),然后,执行一半,又被触发,data_received事件。寻找绑定的处理程序。一个匿名函数,执行,事件全部完成,执行最后一句,程序执行完毕。
多用户执行的情况下,触发事件以后,若处理程序正被其他用户占用,排队,直到前方全部处理完成以后,接着该用户使用处理程序进行处理。

EventEmitter

node所有的异步I/O操作在完成的时候都会发送到一个事件到达事件队列。node里的对象能够分发事件
产生的事件的对象都是events.EventEmitter的实例

EventEmitter类

events模块提供一个对象,它是对事件的触发和事件的监听的封装

PS C:\Users\mingm\Desktop\test> node main.js
事件触发
PS C:\Users\mingm\Desktop\test>

过五秒后响应

// event.js文件
var EventEmitter = require('events').EventEmitter;
var event = new EventEmitter(); // 创建一个event对象
event.on('some_event', function(){console.log('事件触发');});
setTimeout(function(){event.emit('some_event');}, 5000);

大概解释一下这段代码
前两句很简单,后两句说一下,event的对象注册了一个事件的监听器。这个事件的监听器为一个匿名函数,事件名称为some_event,当5000秒以后被触发先对象event发送一个事件some_event触发了匿名函数即监听器,监听器被执行。
其中EventEmitter的每个事件由一个事件名和若干参数组成,对于一个事件能有若干的监听器,当事件触发的时候,监听器会被依次调用,事件参数作为回调函数的参数进行传递,需要注意的是,监听器会被依次调用

error事件

error是一个单独列出来的事件,一般要为其绑定一个监听器,因为node如果抛出error,若没有监听器执行,将会直接退出执行,并返回错误

Buffer缓冲区

处理TCP或者文件流的时候,需要用到二进制的数据,定义了一个Buffer类,该类用于专门存放二进制数据的缓冲区

Buffer与字符编码

const buf = Buffer.from('ming', 'ascii');   // 声明一个只读的变量console.log(buf.toString('hex'));console.log(buf.toString('utf-8'));
PS C:\Users\mingm\Desktop\test> node main.js
6d696e67
ming
PS C:\Users\mingm\Desktop\test>

创建一个buffer类,并完成读取写入

PS C:\Users\mingm\Desktop\test> node main.js
23456789:;<=>?@ABCDEFGHIJK
23456789:;<=>?@ABCDEFGHIJK
PS C:\Users\mingm\Desktop\test>
buf = Buffer.alloc(26);
for(var i = 0; i < 26; i++){buf[i] = 50 + i;
};
console.log(buf.toString('ascii'));
console.log(buf.toString('utf8'));

将buffer转换为jsoon

PS C:\Users\mingm\Desktop\test> node main.js
{"type":"Buffer","data":[1,2,3,4,5]}
PS C:\Users\mingm\Desktop\test>
const buf = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5]);
const json = JSON.stringify(buf);console.log(json);

将JSON转换为Buffer

一个转换方法JSON.parse

> JSON.parse('{"1": 3, "2": [4, 5, 6]}', function (k, v) {
...     console.log(k); // 输出当前的属性名,从而得知遍历顺序是从内向外的,
...     console.log("----------");              // 最后一个属性名会是个空字符串。
...     console.log(v);
... });
1
----------
3
0
----------
4
1
----------
5
2
----------
6
2
----------
[ <3 empty items> ]----------
{}
undefined
>

开始转换

const buf = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5]);
const json = JSON.stringify(buf);console.log(json);const copy = JSON.parse(    // 调用JSON.parse函数,将字符串转换为对象,后一个参数为转换的函数,转换的时候将会调用json,(key, value) => {   // 此为es6的语法,一个匿名函数console.log(value, '----', !!value, '----', value.type, '-----', value.data);return value && value.type === 'Buffer' ? Buffer.from(value.data): value;   // 只留下最后一个进行转换,前面的转换全部被覆盖})// 输出: <Buffer 01 02 03 04 05>
console.log(copy);
PS C:\Users\mingm\Desktop\test> node main.js
{"type":"Buffer","data":[1,2,3,4,5]}
Buffer ---- true ---- undefined ----- undefined
1 '----' true '----' undefined '-----' undefined
2 '----' true '----' undefined '-----' undefined
3 '----' true '----' undefined '-----' undefined
4 '----' true '----' undefined '-----' undefined
5 '----' true '----' undefined '-----' undefined
[ 1, 2, 3, 4, 5 ] '----' true '----' undefined '-----' undefined
{ type: 'Buffer', data: [ 1, 2, 3, 4, 5 ] } '----' true '----' 'Buffer' '-----' [ 1, 2, 3, 4, 5 ]
<Buffer 01 02 03 04 05>
PS C:\Users\mingm\Desktop\test>

Buffer的合并

var buffer1 = Buffer.from('222');
var buffer2 = Buffer.from('3333');
var buffer3 = Buffer.concat([buffer1, buffer2]);
console.log(buffer3.toString());

Stream流

流为一个抽象的接口,

从流中读取数据

PS C:\Users\mingm\Desktop\test> node main.js
end!
33333333333333333333333333
PS C:\Users\mingm\Desktop\test>
var fs = require('fs');
var data = '';// 创建可读流
var readerStream = fs.createReadStream('input.txt');// 设置编码为 utf8
readerStream.setEncoding('UTF8');// 处理流事件 data事件
readerStream.on('data', (chunk) => {data += chunk;});   // 遇到数据读取,将读取到的内容赋值给data// 处理流事件 end事件
readerStream.on('end', () => {console.log(data);}); // 将读取到的保存到内存中的数据打印出来// 处理事件 error
readerStream.on('error', (err) => {console.log(err.stack);});   // 处理error事件,将错误输出,避免程序的运行中断console.log('end!');

写入流

PS C:\Users\mingm\Desktop\test> node main.js
程序执行完毕
写入完成
PS C:\Users\mingm\Desktop\test>
var fs = require('fs');
var data = '这是一段示例';// 创建一个可以写入的流,写入到文件output.txt中
var writerStream = fs.createWriteStream('output.txt');// 使用 utf8 编码写入数据
writerStream.write(data, 'UTF8');// 标记文件末尾
writerStream.end();// 处理流事件 --> data, end, add error
writerStream.on('finish', () => {console.log('写入完成');});writerStream.on('error', () => {console.log(err.stack);});console.log('程序执行完毕');

管道流

把两个文件之间建立流,让一个文件的数据流向另外一个文件

PS C:\Users\mingm\Desktop\test> node main.js
程序执行完毕
PS C:\Users\mingm\Desktop\test>
var fs = require('fs');// 创建一个可读流
var readerStream = fs.createReadStream('input.txt');// 创建一个可写流
var writerStream = fs.createWriteStream('output.txt');// 管道读写操作
// 将两个流通过管道连接起来
readerStream.pipe(writerStream);console.log('程序执行完毕');

这里需要注意的是,由于流的影响,导致在操作的时候,会覆盖掉要写入文件的内容,原先的内容会被覆盖

链式流

PS C:\Users\mingm\Desktop\test> node main.js
文件压缩完成
PS C:\Users\mingm\Desktop\test>
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 read = fs.createReadStream('output.txt');
var write = fs.createWriteStream('input.txt');
read.pipe(write);
console.log('执行完毕');

具体详细,请查文档
https://nodejs.org/api/fs.html#fs_fs_createwritestream_path_options
https://nodejs.org/api/fs.html#fs_file_system_flags
文档写的很详细,后面的参数为一个对象,通过对象即可进行修改

模块

模块之前已经阐述过一部分,这里阐述服务器端的模块

服务器端的模块

node中自带了一个http模块,在代码中请求他,并将返回值赋值给本地变量。即本地变量变成了一个拥有所有http模块所提供的公共方法的对象。
node中有四个模块,(原生模块和三种文件模块)

从文件模块的缓存中添加

原生模块和文件模块优先级不同,都会优先从文件模块的缓存中加载以及存在的模块

从原生模块加载

原生模块的优先级低于文件模块缓存的优先级。原生模块也有缓存区

从文件加载

这个上一篇以及阐述完成,不在阐述

node事件循环 EventEmitter 异步I/O Buffer缓冲区 模块相关推荐

  1. node事件循环 EventEmitter 异步I/O Buffer缓冲区 模块

    node.js事件循环 node.js单进程,单线程的程序 每一个api都支持回调 所有的事件机制都是设计模式中的 一共是23种设计模式 http://design-patterns.readthed ...

  2. 浏览器与node事件循环

    我们都知道在浏览器中由于dom操作,js是单线程的. 为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得 ...

  3. 浏览器和node事件循环

    什么是事件循环 每一个浏览器都至少有一个事件循环,一个事件循环至少有一个任务队列.循环指的是其永远处于一个"无限循环"中.不断将注册的回调函数推入到执行栈 浏览器的事件循环标准是由 ...

  4. JavaScript执行机制-node事件循环

    node环境下的事件循环机制 和浏览器有什么不同? 在node中,事件循环表现出来的状态和浏览器大致相同,但是node有一套自己的模型. node事件循环依靠libuv引擎,node选择chrome ...

  5. 浏览器事件循环与node事件循环

    前言 最近看到一些关于 事件队列,浏览器执行机制的文章推荐,联想到很早以前遇到的一些面试题,才惊觉自己对这块一直都不怎么了解,借助这个机会好好记录一番.顺便感叹一句,阮一峰大神的 blog真是应有尽有 ...

  6. JavaScript是如何工作的:事件循环和异步编程的崛起+ 5种使用 async/await 更好地编码方式!...

    此篇是 JavaScript是如何工作的第四篇,其它三篇可以看这里: JavaScript是如何工作的:引擎,运行时和调用堆栈的概述! JavaScript是如何工作的:深入V8引擎&编写优化 ...

  7. JavaScript 如何工作的: 事件循环和异步编程的崛起 + 5 个关于如何使用 async/await 编写更好的技巧...

    原文地址:How JavaScript works: Event loop and the rise of Async programming + 5 ways to better coding wi ...

  8. [译] JavaScript 如何工作的: 事件循环和异步编程的崛起 + 5 个关于如何使用 async/await 编写更好的技巧...

    原文地址:How JavaScript works: Event loop and the rise of Async programming + 5 ways to better coding wi ...

  9. jsp循环输出表格_「翻译」JS可视化学习之七:Promise、事件循环和异步2

    喜欢排队吧,它能保护你的时间和精力 - 排队纪律维护员Event Loop Promise和事件循环概览图 请注意上面这张图,Promise和事件循环的那些事,将在这个图上缓缓展开. 微任务和(宏)任 ...

最新文章

  1. ubuntu开辟虚拟内存
  2. 【数据库】阿里云教你快速掌握SQL语句使用
  3. Linux中文件描述符1,linux内核中的文件描述符(一)--基础知识简介
  4. android 在一个Activity(A)中结束另一个Activity(B)
  5. quartz(6)--集群
  6. python每日一练名片管理程序_Python每日一练0022
  7. centos linux 系统日常管理4 scp,rsync,md5sum,sha1sum,strace ,find Rsync 常见错误及解决方法 第十七节课...
  8. 排序算法之两路归并排序(Java)
  9. Android官方开发文档Training系列课程中文版:高效显示位图之位图缓存
  10. 金士顿u盘真假软件_简洁轻巧 金士顿DT80 Type-C高速闪存盘评测
  11. 多线程读取大文件,尤其是对日志文件分析很有用。
  12. SharePoint2010升级到SharePoint2013操作手册
  13. NLP中GLUE数据集下载
  14. oracle redo log file文件详解
  15. VS2015+WDK10+Win10 Win7以上系统驱动发开环境搭建
  16. 大厂“降本增效”后招聘要求,这项目经验和技术能力...,绝了
  17. windows7系统如何实现AirPrint打印
  18. Sdk4J.jar安装到本地maven仓库
  19. POJ 3233 Matrix Power Series(矩阵快速幂)
  20. 一加和华为买哪个好 一加9用新特性赢得消费者口碑

热门文章

  1. 05Vue.js快速入门-Vue实例详解与生命周期
  2. Linux-insmod/rmmod/lsmod驱动模块相关命令(10)
  3. Thinkphp3.2整合微信支付
  4. PHP curl 使用代码
  5. 基于PHP采集数据入库程序(二)
  6. 测试centos x64 6.2安装oracle 11G
  7. 利用 Domino V8 新特性开发 Mashup 应用(转载)
  8. 算法高级(9)-线程池的实现方式
  9. 只腐蚀毛刺 腐蚀算法_去毛刺更省时省力的方式方法大全!
  10. ios 旋转屏幕试图切换_TCL·XESS 旋转智屏 A200Pro 评测:方向一换,体验大不相同...