node开发的那些小事

352 阅读7分钟

一直以来被node的神秘深深吸引,于是在2020年七夕节,想要和node关系更进一步,开始揭开他神秘的面纱~

1.what:什么是node?

官方给出答案:

Node.js 就是运行在服务端的 JavaScript。

Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台。

Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好

其实我还是不懂。但是继续往下学习。。。。万一某个瞬间 就懂了呢

2 what:node有什么特点?

1.异步io 2.事件和回调函数 3.单线程:保持了js单线程特点 4.跨平台:基于libuv实现跨平台

3.why:什么场景适合用node?

io密集型:node利用事件循环处理能力,而不是启动每一个线程为每一个请求服务,资源占用极少 cpu密集型:v8的执行效率非常高,

总的来说 高并发、I/O密集、少量业务逻辑的场景。

1.node用来做什么? 搜索引擎优化,网页首屏加速 = 服务端渲染

4.how:怎么使用node?

1.创建一个http服务

var http = require('http'); 
http.createServer(function (req, res) { 
 res.writeHead(200, {'Content-Type': 'text/plain'}); 
 res.end('Hello World\n'); 
}).listen(1337, '127.0.0.1'); 
console.log('Server running at http://127.0.0.1:1337/');

2.模块化

Nodejs端是使用CommonJS规范的,前端浏览器一般使用AMD、CMD、ES6等定义模块化开发的

1>commont.js 是通过module.exports定义的,在前端浏览器里面并不支持module.exports,通过node.js后端使用的。

输出方式有2种:默认输出---module export 和带有名字的输出---exports.area

exports.area = function(r){
return Math.PI*r*r;
};


2>CMD 同步 在依赖的部分 cmd支持动态引入,

于AMD相比,amd需要在声明模块的时候指定所有的依赖,通过形参传递依赖熬模块内容中:

amd:
define(['dep1', 'dep2'], function (dep1, dep2) {
 return function () {};
}); 

cmd:
define(function(require, exports, module) {
 // The module code goes here
}); 

require, exports, module 通过形参传递给模块,在需要依赖模块时,随时调用require()引入即可。 3>AMD 异步

eg如下: 他的模块id和依赖是可选的。

与node相似的地方:factory 的内容就是实际代码的内容。 不同地方:AMD 模块需要用define来明确定义一个模块,而在node实现中是隐式包装的,他的目的是进行作用域的隔离,仅在需要的时候被引入,避免掉过去那种通过全局变量或全局命名空间的方式,以免变量污染和不小心修改,内容需要通过返回的方式导出。

define(id?, dependencies?, factory);
define(function() {
 var exports = {};
 exports.sayHello = function() {
 alert('Hello from module: ' + module.id);
 };
 return exports;
});

3.node操控文件系统(原生)

对于绝大多数的pi来说,node都提供了相同功能的俩个版本: 同步版本/异步版本
同步和异步在命名上存在以下规则:
xxx 异步/xxxsync 同步
尽最大可能使用异步版本
若 文件内容多,则用 fs.createWriteStream(path[, options]) 和fs.createReadStream(path[, options]),具体事例参考官方node api
eg:
const fs = require('fs')

fs.rename('before.json', 'after.json', err => {
  if (err) {
    return console.error(err)
  }

  //完成
})

const fs = require('fs')

try {
  fs.renameSync('before.json', 'after.json')
  //完成
} catch (err) {
  console.error(err)
}

4.buffer

Buffer是一个像Array的对象,但他主要用于操作字节 所有的数据传输到最底层,全是二进制,在传输的过程中,字符也就是01这类编码是一个一个被从一个地方取出来又放到另一个地方去的,没有缓冲的话,只有一个字符被发送者发出后才能取到,一旦发送和取出的速度不一致,就会出现数据传输卡顿甚至断流, 所以加了缓冲器,发送者把数据全部放在缓冲期里,接受者去里面取,这样只要缓冲器里还有数据,接受者接收数据就不会卡顿,甚至发送者突然卡死,接受者也可以拿到数据。不会出现数据卡顿。只要在接受者取完缓冲器里的数据之前,发送者可以继续存放,数据就依然正常传输,视频里的缓存就是这个效果

5.建立udp服务

udp服务端
 dgram = require("dgram"); 
var server = dgram.createSocket("udp4");  // 创建一个udp套接字
server.on("message", function (msg, rinfo) { 
 console.log("server got: " + msg + " from " + 
 rinfo.address + ":" + rinfo.port); 
}); 
server.on("listening", function () { 
 var address = server.address(); 
 console.log("server listening " + 
 address.address + ":" + address.port); 
}); 
server.bind(41234);
客户端
var dgram = require('dgram'); 
var message = new Buffer("ศ入റ出Node.js"); 
var client = dgram.createSocket("udp4"); 
client.send(message, 0, message.length, 41234, "localhost", function(err, bytes) { 
 client.close(); 
});

socket.send(buf, offset, length, port, address, [callback]) 这些参数分别要发送buffer, buffer偏移,buffer长度,目标端口,目标地址,发送完成后的回调

6.建立tcp服务

通过net.createServer(listener)创建一个tcp服务器,listener是连接事件connection的侦听器,也可以用如下方式进行侦听:var server = net.createServer(); server.on('connection', function (socket) { // ႎ的૶接 }); server.listen(8124);

tcp服务端
var net = require('net'); 
var server = net.createServer(function (socket) { 
 // ႎ的૶接
 socket.on('data', function (data) { 
 socket.write("ేࡻ"); 
 }); 
 socket.on('end', function () { 
 console.log('૶接܏开'); 
 }); 
 socket.write("࣌ᆓ࠼ଣĖศ入റ出Node.jsė๖૩:\n"); 
}); 
server.listen(8124, function () { 
 console.log('server bound'); 
});
客户端

var net = require('net'); 
var client = net.connect({port: 8124}, function () { //'connect' listener 
 console.log('client connected'); 
 client.write('world!\r\n'); 
}); 
client.on('data', function (data) { 
 console.log(data.toString()); 
 client.end(); 
}); 
client.on('end', function () { 
 console.log('client disconnected'); 
});

tcp:传输控制协议,osi模型中分为7层(物理层,数据链结层,网络层,网络层,传输层,会话层,表示层,应用层),属于传输层。tcp是面向连接的协议,特征:在传输之前要进行3次握手形成会话,会话行成之后,客户端和服务端能相互发送数据。在服务端和客户端分别提供一个套接字。tcp连接一旦建立,所有会话都基于连接完成。

udp:用户数据包协议,和tcp一样属于网络传输层。和tcp最大的不同,udp不是面向连接的,一个套接字可以与多个UDP服务通信,它虽然提供面向事物的简单不可靠信息传输服务。在网络差的情况下存在丢包严重的问题,但是由于它无需连接,资源消耗低,处理快速且灵活,所以常常应用到 丢一两个数据包也不会产生重大影响的场景。比如(音频 视频),udp应用很广泛,dns是基于它实现的。

http:超文本传输协议,http构建在tcp之上,属于应用层协议

https:

websocket:实现了客户端与服务端的长连接,而node事件驱动的方式十分擅长与大量的客户端保持高并发连接,相比较tcp,他是双向通信。 主要分为握手和数据传输。一旦握手成功,服务端和客户端会呈现对等的效果,都能发送和接收消息。

网络服务和安全:ssl 安全协议,他在传输层提供对网络连接加密的功能。对于应用层而言 他是透明的。

7.建立socket.io服务(客户端/服务端)

8.异步io与线程池

io:即input/output,一个系统的输入和输出

阻塞io和非阻塞io区别:系统接收输入再到输出期间,能不能接收其他输入

如何理解 阻塞io和非阻塞io:1》先确定一个进行input/output系统2》思考在I/O过程中能不能进行其他I/O

同步阻塞io:就是cpu既要监控数据是否就绪,还要负责数据的读取

同步非阻塞io:就是等数据就绪后,会有人通知我去读取数据

异步io:就更骚操作了,等数据读取好了后,再告诉我

事件循环:

异步编程解决方案: 1、事件发布/订阅模式 2、promise/deferred模式 3、流程控制库

异步编程: 1.callback() 2.promise 3.async/await 4.Generator

9.连接数据库

10.连接redis

11.子进程与主子进程通信

12.内存控制

内存泄漏的原因:1.缓存 2.队列消费不及时 3.作用域未释放

闭包:在js'中,实现外部作用域访问内部作用域中变量的方法就是闭包

排查内存泄漏的原因,主要是通过对堆内存进行分析而找到node-heapdump和node-memwatch各有所长

集群 分布式

集群 就是派多个一样的人干同一个活

分布式就是把一个活分工分成不同任务,找不同的人干

业务复杂的时候用分布式,任务量大的时候用集群

备注:

BFF层 backend for Frontend

使用后端的RPC服务 对用户侧提供http服务

npm包是什么? node.js的包管理工具。 包是什么? 别人写的node.js模块。