初识NodeJS

本文主要基于极客时间《Nodejs开发实战》课程。
本篇(一)为课程的第二篇——技术预研篇。

什么是Nodejs?

来源官网:

  • Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。
  • Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。

在Chrome里写NodeJS和在NodeJS里写JS有区别吗?
几乎没有区别,因为都是用V8引擎编译和解释,唯一的区别在于:NodeJS中没有浏览器API,没有浏览器环境变量window、document等等,却多了NodeJS API,比如文件系统、进程管理等。

NodeJS可以做什么?

  1. web服务中间层,搜索引擎优化(SEO)、网页首屏加速。
  2. 服务端渲染+前后端同构
  3. 构建工作流、做JS构建工具(Gulp、webpack等),给各个类型文件做预编译、压缩等,模板预编译、将less转为css,将js压缩混淆等。
  4. Visual Studio Code 是使用NodeJS开发的,甚至可以使用Node编写vscode插件vscode编写插件详细过程
  5. 游戏开发,JS有利于开发扩展模块等。
  6. 客户端应用,在已有网站前提下开发新的客户端应用,可以使用NodeJS客户端技术(electron)(都是使用V8 引擎的底层解释),最大限度复用现有工程。

常见Node 特有API

可以直接创建一个js文件试一下,执行Node命令只需要输入node + js名称 即可。
特有常见环境变量:

  1. __filename: 当前脚本运行所在位置
  2. __dirname: 当前脚本运行所在的目录位置
  3. process:进程对象(运行Node时的运行环境信息)

node版本号version/versions,当前操作系统plantform等
kill / exit 一些管理 / 杀进程操作会使用
hrtime(function:bigint) 时间精度统计
cpuUsage cpu占用率,性能分析时有用
memoryUsage 内存占用率,同上。
env 运行时的环境变量对象集合,Node运行时可以使用env识别改变运行环境,比如正式、测试、本地、debug
argv 用户运行进程时敲击命令记录数组,最新的命令将push到数组的最后一行,如果程序中用到命令行可以使用这个属性。
 比如:node index.js test ,也就是以test命令运行node.js,打印argv,最后一个数就是test。

argv实战测试-一个简单的命令行输入和电脑做石头剪刀布
// index.js
const playerAction = process.argv[process.argv.length-1];
const computerAction = Math.random()*3 <1 ? 'rock': Math.random()*3 <2 ? 'scissor':'paper';
console.log(playerAction,computerAction)
const win = {rock:'paper',scissor:'rock',paper:'scissor'
}if(computerAction === playerAction){console.log('平局')
}else{if(win[playerAction] === computerAction){console.log('电脑胜')}else{console.log('玩家胜')}
}node index.js scissor 执行,argv取出的最后一个命令(玩家出的)的就是scissor

Node模块(CommonJS规范)

NodeJS模块中文官方文档
NodeJS模块英文官方文档

NodeJS的内置模块都放置于Node源码中的lib文件夹下。其实Node获取到操作系统相关信息能力并不是JS提供的,而是V8引擎中C++底层提供的方法,Node提供的很多内置方法其实是对Node中C++模块的封装调用,由此实现Node和操作系统之间的交互。

FileSystem
OS
  1. os.arch()
    方法返回一个字符串, 表明 Node.js 二进制编译所用的 操作系统CPU架构。现在可能的值有: ‘arm’, ‘arm64’, ‘ia32’, ‘mips’, ‘mipsel’, ‘ppc’, ‘ppc64’, ‘s390’, ‘s390x’, ‘x32’, ‘x64’。
    等价于 process.arch。
  2. os.cpus()
    返回一个对象数组, 包含每个逻辑 CPU 内核的信息
  3. os.freemem()
    查看还有多少空余内存
Process
Net
Buffer

处理二进制数据,用于处理网络协议、TCP文件流、数据库、图片、上传接受文件等。

在Node应用中,需要处理网络协议、操作数据库、处理图片、接收上传文件等,在网络流和文件的操作中,要处理大量二进制数据,而Buffer就是在内存中开辟一片区域(初次初始化为8KB),用来存放二进制数据
在上述操作中都会存在数据流动,每个数据流动的过程中,都会有一个最小或最大数据量
如果数据到达的速度比进程消耗的速度快,那么少数早到达的数据会处于等待区等候被处理。反之,如果数据到达的速度比进程消耗的数据慢,那么早先到达的数据需要等待一定量的数据到达之后才能被处理
这里的等待区就指的缓冲区(Buffer),它是计算机中的一个小物理单位,通常位于计算机的 RAM 中

简单来讲,Nodejs不能控制数据传输的速度和到达时间,只能决定何时发送数据,如果还没到发送时间,则将数据放在Buffer中,即在RAM中,直至将它们发送完毕

  1. 创建

Buffer.from() 将数据转为Buffer Buffer.from('test') | ([1,2,3])
Buffer.alloc() 创建一个固定长度的Buffer区间

const buffer = Buffer.from("你好");
console.log(buffer);
// <Buffer e4 bd a0 e5 a5 bd>
const str = buffer.toString();
console.log(str);
// 你好

支持的字符集如下:

  • ascii:仅支持 7 位 ASCII 数据,如果设置去掉高位的话,这种编码是非常快的
  • utf8:多字节编码的 Unicode 字符,许多网页和其他文档格式都使用 UTF-8
  • utf16le:2 或 4 个字节,小字节序编码的 Unicode 字符,支持代理对(U+10000至 U+10FFFF)
  • ucs2,utf16le 的别名
  • base64:Base64 编码
  • latin:一种把 Buffer 编码成一字节编码的字符串的方式
  • binary:latin1 的别名,
  • hex:将每个字节编码为两个十六进制字符
  1. 读写
    Buffer打印出来是一串由两位(16进制)的数字组成的类似数组的结构
    Buffer.writeInt8 、Buffer.writeInt16等等
    读写中区分一个LE(高位放在后面)/BE(高位放在前面)的区别,即读取/写入的顺序是大端还是小端,根据设备来决定。
    第三方编解码库:protocol-buffers
http
  1. 建立一个简单的http服务
const http = require('http');http.createServer( (req,res)=> {if(req.url === /favicon.ico'){res.whiteHead(200);res.end();return;}res.writeHead(200);res.end('hello');
}).listen(3100)const http = require('http');// 返回html,使用fs文件模块输出html文件流
const fs = request('fs)
http.createServer( (req,res)=> {res.writeHead(200);fs.createReadStream(__dirname+'/index.html').pipe(res)
}).listen(3100)
  1. 认识request / response对象
  • request
    在请求响应中 console.log(req),可以发现req对象其实是一个叫做IncommingMessage的对象,而这个对象的详细内容都可以在Node文档官网中找到:网址:http://caibaojian.com/nodejs/api/en/http.html#http_class_http_incomingmessage

url
aborted 是否是中断请求
headers
method

在请求url中有一个特殊的url,不是客户端发起的,而是浏览器发起的url,用于请求标签页上的icon ,此url为:/favicon.ico,如果不想这个额外url引起额外的跳转问题,需要注意。比如用户发起一个/page/1页面的请求,实际上服务器会接受到两个请求,一个是/favicon.ico,另一个才是/page/1

  • response
    response对象同理,在Node文档中有一个专门的ServerResponse对象。
  1. Express / Koa 处理
url
  1. url.parse 会返回一个Url对象
    内部数据参考如下:
console.log(url.parse(req.url))
Url {protocol: null,slashes: null,auth: null,host: null,port: null,hostname: null,hash: null,search: null,query: null,pathname: '/',path: '/',href: '/'
}
  1. 或者直接new URL对象
    const myURL = new URL(‘https://user:pass@sub.host.com:8080/p/a/t/h?query=string#hash’);
┌─────────────────────────────────────────────────────────────────────────────────────────────┐
│                                            href                                             │
├──────────┬──┬─────────────────────┬─────────────────────┬───────────────────────────┬───────┤
│ protocol │  │        auth         │        host         │           path            │ hash  │
│          │  │                     ├──────────────┬──────┼──────────┬────────────────┤       │
│          │  │                     │   hostname   │ port │ pathname │     search     │       │
│          │  │                     │              │      │          ├─┬──────────────┤       │
│          │  │                     │              │      │          │ │    query     │       │
"  https:   //    user   :   pass   @ sub.host.com : 8080   /p/a/t/h  ?  query=string   #hash "
│          │  │          │          │   hostname   │ port │          │                │       │
│          │  │          │          ├──────────────┴──────┤          │                │       │
│ protocol │  │ username │ password │        host         │          │                │       │
├──────────┴──┼──────────┴──────────┼─────────────────────┤          │                │       │
│   origin    │                     │       origin        │ pathname │     search     │ hash  │
├─────────────┴─────────────────────┴─────────────────────┴──────────┴────────────────┴───────┤
│                                            href                                             │
└─────────────────────────────────────────────────────────────────────────────────────────────┘
(all spaces in the "" line should be ignored — they are purely for formatting)

有了url对象后,我们就可以比较方便地处理响应路径了

const http = require('http');
const url = require('url);http.createServer( (req,res)=> {const parseUrl = url.parse(req.url);if(parseUrl.pathname === /favicon.ico'){res.whiteHead(200);res.end();return;}if(parseUrl.pathname === /test/interface'){const query = qs(parseUrl.query);res.end(`${query}_1`);return;}if(parseUrl.pathname === /'){res.writeHead(200);res.end('hello');}}).listen(3100)
Events 事件

因为Node大部分核心API都采用异步驱动的方式,所以为异步任务“标记命名”和“监听触发”就成了Node中一个非常常见的行为。
比如net.Server 对象会在每次有新连接时触发事件;fs.ReadStream 会在文件被打开时触发事件;流对象 会在数据可读时触发事件。
所有能触发事件的对象都是 EventEmitter 类的实例(从这个角度上来说,任何可以被监听的对象都是EventEmitter实例)。这些对象会继承EventEmitter实例的方法eventEmitter.on(),允许将一个或多个函数绑定到会被对象触发的命名事件上。
例:

// 一个绑定了一个监听器的 EventEmitter 实例。 eventEmitter.on() 方法用于注册监听器,eventEmitter.emit() 方法用于触发事件。
const EventEmitter = require('events');class MyEmitter extends EventEmitter {constructor(){super();setInterval(()=>{this.emit('event',{"参数":"参数值"})// 测试:process.exit();},3000)}
}const myEmitter = new MyEmitter();
myEmitter.on('event', (res) => {console.log('触发了一个事件!',res);
});

以上监听和触发的行为,就实现了观察者模式。

  • Class: EventEmitter EventEmitter实例拥有下列常见方法

emitter.addListener(eventName, listener)
emitter.removeListener(eventName, listener)
emitter.emit(eventName[, …args])

emitter.on(eventName, listener) (效果等于addListener
emitter.once(eventName, listener)

异步IO

事件循环

事件循环是非阻塞IO的基础,而且非阻塞IO和事件循环是LIBUV的重要组成成分。
Node中的异步事件执行在其他线程中,等到执行完成将消息通知到JS执行主线程进行任务回调处理。

function eventloop() {const queue = []; // 消息队列,异步任务已经执行完后将结果Push此处const loop = ()=>{while(queue.length){const callback = queue.shift();callback?.();}// 假设50ms一个循环时间片,处理消息队列中的数据setTimeout(()=>{loop();},50)}const add = (callback)=>{queue.push(callback)}return {loop,add}
}const LOOP = eventloop();LOOP.loop();
setTimeout(()=>{LOOP.add(()=>{console.log("500 ms")})
},500)setTimeout(()=>{LOOP.add(()=>{console.log("800 ms")})
},800)

NodeJS异步编程方案

  1. async / await 异步写法同步化,一个穿越事件循环存在的function
  2. Promise

RPC调用

Remote Procedure Call(远程过程调用)

  • 两个计算机之间的网络通信
  • 需要双方约定一个共同格式
  • 一般是在内网中互相调用服务,而不像前端常见的请求服务器需要使用DNS寻址。
  • 应用层协议通常采用一些二进制协议而非HTTP,有性能优势
  • 基于TCP / UDP协议

以AJAX使用类比举例

  • 寻址
    Ajax 使用DNS进行寻址 路径通常为:http://域名/ ,然后通过DNS服务器将域名转化为IP,才能发起请求
    RPC 使用特有的服务进行寻址,以一个标识符来标识内网中的各个服务地址
  • 通信
    RPC 往往使用TCP通信,可能存在 单工通信 / 半双工通信(轮番单工通信) / 全双工通信等。
  • 二进制协议
    http协议是一个文本协议,大多时候文本格式为html或者json格式
    RPC采用二进制协议,可以有更小的数据包体积&更快的编解码速率。

实战结合

Node主要做BFF层(Backend for Frontend)
具体内容请看初识Node第二篇。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2775502.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

计算机网络相关题目及答案(第八章)

第八章 习题&#xff1a; P19. 考虑下面对于某 SSL会话的一部分的Wireshark输出。 a. Wireshark分组112是由客户还是由服务器发送的? b.服务器的IP地址和端口号是什么? c.假定没有丢包和重传&#xff0c;由客户发送的下一个TCP报文段的序号将是什么? d. Wireshark分组…

(十七)springboot实战——spring securtity的授权流程源码解析

前言 本节内容是关于spring security安全框架授权流程的源码分析&#xff0c;spring security的授权流程主要是在FilterSecurityInterceptor过滤器中实现的。我们会通过源码层级的分析&#xff0c;了解清楚spring security的底层是如何实现用户授权的。 正文 1.配置一个请求…

【LeetCode每日一题】525连续数组 303区域和检索(前缀和的基本概念和3个简单案例)

前缀和 // 构造prefix let prefix [0] arr.forEach(num > {prefix.push(prefix.at(-1) num); })如果想要计算某个区间 i 到 j 这个子数组的和时&#xff0c;可以根据 prefix[j1] - prefix[i] 获得。 例题1&#xff1a;303.区域和检索 - 数组不可变 给定一个整数数组 num…

【stomp实战】websocket原理解析与简单使用

一、WebSocket 原理 WebSocket是HTML5提供的一种浏览器与服务器进行全双工通讯的网络技术&#xff0c;属于应用层协议。它基于TCP传输协议&#xff0c;并复用HTTP的握手通道。浏览器和服务器只需要完成一次握手&#xff0c;两者之间就直接可以创建持久性的连接&#xff0c; 并…

有道ai写作,突破免费限制,无限制使用

预览效果 文末提供源码包及apk下载地址 有道ai写作python版 import hashlib import time import json import ssl import base64 import uuidfrom urllib.parse import quote import requests from requests_toolbelt.multipart.encoder import MultipartEncoder from Crypto…

Redis核心技术与实战【学习笔记】 - 27.限制Redis Cluster规模的因素(通信开销)

简述 Redis Cluster 能保存的数据量以及支撑的吞吐量&#xff0c;跟集群实例规模相关。 Redis 官方给出了 Redis Cluster 的规模上线&#xff0c;就是一个集群运行 1000 个实例。 其实&#xff0c;限定 Redis Cluster 集群规模的一个关键因素就是&#xff0c;实例间的通信开销…

TCP 传输控制协议

1 TCP 1.1 TCP 最主要的特点 1.TCP 是面向连接的运输层协议。 2.每一条 TCP 连接只能有两个端点 (endpoint)&#xff0c;每一条 TCP 连接只能是点对点的&#xff08;一对一&#xff09;。 3.TCP 提供可靠交付的服务。 4.TCP 提供全双工通信。 5.面向字节流 TCP 中的“流…

力扣刷题之旅:进阶篇(二)

力扣&#xff08;LeetCode&#xff09;是一个在线编程平台&#xff0c;主要用于帮助程序员提升算法和数据结构方面的能力。以下是一些力扣上的入门题目&#xff0c;以及它们的解题代码。 继续我的力扣刷题之旅&#xff0c;在上一篇文章中&#xff0c;我深入探索了图算法和动态…

Unity3d Shader篇(六)— BlinnPhong高光反射着色器

文章目录 前言一、BlinnPhong高光反射着色器是什么&#xff1f;1. BlinnPhong高光反射着色器的工作原理2. BlinnPhong高光反射着色器的优缺点优点缺点 3. 公式 二、使用步骤1. Shader 属性定义2. SubShader 设置3. 渲染 Pass4. 定义结构体和顶点着色器函数5. 片元着色器函数 三…

Ubuntu22.04 gnome-builder gnome C 应用程序习练笔记(一)

一、序言 gnome-builder构建器是gnome程序开发的集成环境&#xff0c;支持主力语言C, C, Vala, jscript, python等&#xff0c;界面以最新的 gtk 4.12 为主力&#xff0c;将其下版本的gtk直接压入了depreciated&#xff0c;但gtk4.12与普遍使用的gtk3有很大区别&#xff0c;原…

【BUUCTF N1BOOK】[第九章 CTF之MISC章] 通关

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【python】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏…

VMwawre配置静态ip

1、查看当前虚拟机网关&#xff08;记住这个网关&#xff0c;后面使用&#xff09; 2、进入目录命令&#xff1a;cd /etc/sysconfig/network-scripts/ 3、编辑网卡配置文件命令&#xff1a;vim ifcfg-ens33 4、配置静态IP&#xff0c;修改和增加如下信息&#xff1a; 修改的内…

vue3 之 商城项目—一级分类

整体认识和路由配置 场景&#xff1a;点击哪个分类跳转到对应的路由页面&#xff0c;路由传对应的参数 router/index.js import { createRouter, createWebHashHistory } from vue-router import Layout from /views/Layout/index.vue import Home from /views/Home/index.vu…

【网工】华为设备命令学习(Telnet)

本次实验AR3为我们实际中远程的路由&#xff0c;AR4模拟我们的设备&#xff0c;最终实现Telnet的远程控制路由&#xff01; 本次笔记主要记录Telnet技术实现原理&#xff0c;后续再补充具体配置代码。 Telnet协议是TCP/IP协议族中的一员&#xff0c;是Internet远程登录服务的…

哈希表—闭散列

目录 背景 实现 设置状态 存储 获取key函数 构造函数 插入 查找 删除 打印 完整代码 背景 常用哈希函数 除留取余法 设散列表中允许的地址数为m&#xff0c;取一个不大于m&#xff0c;但最接近或者等于m的质数p作为除数&#xff0c;按照哈希 函数&#xff1a;H a…

ubuntu22.04安装部署03: 设置root密码

一、前言 ubuntu22.04 安装完成以后&#xff0c;默认root用户是没有设置密码的&#xff0c;需要手动设置。具体的设置过程如下文内容所示&#xff1a; 相关文件&#xff1a; 《ubuntu22.04装部署01&#xff1a;禁用内核更新》 《ubuntu22.04装部署02&#xff1a;禁用显卡更…

山西电力市场日前价格预测【2024-02-08】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2024-02-08&#xff09;山西电力市场全天平均日前电价为200.58元/MWh。其中&#xff0c;最高日前电价为347.58元/MWh&#xff0c;预计出现在07:00。最低日前电价为0.00元/MWh&#xff0c;预计出…

数据结构 - 线索树

一、 为什么要用到线索二叉树&#xff1f; 我们先来看看普通的二叉树有什么缺点。下面是一个普通二叉树&#xff08;链式存储方式&#xff09;&#xff1a; 乍一看&#xff0c;会不会有一种违和感&#xff1f;整个结构一共有 7 个结点&#xff0c;总共 14 个指针域&#xff0c…

【多模态】27、Vary | 通过扩充图像词汇来提升多模态模型在细粒度感知任务(OCR等)上的效果

文章目录 一、背景二、方法2.1 生成 new vision vocabulary2.1.1 new vocabulary network2.1.2 Data engine in the generating phrase2.1.3 输入的格式 2.2 扩大 vision vocabulary2.2.1 Vary-base 的结构2.2.2 Data engine2.2.3 对话格式 三、效果3.1 数据集3.2 图像细粒度感…

云安全的基本概念(基本目标与指导方针)

目录 一、云安全概念概述 1.1 概述 二、云安全的基本目标 2.1 安全策略开发模型 2.1.1 信息安全三元组 2.1.1.1 保密性(Confidentiality) 2.1.1.2 完整性(Integrity) 2.1.1.3 可用性(Availability) 2.1.2 信息安全三元组的局限性 2.2 其他信息安全属性 2.2.1 真实性 …