初识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第二篇。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【网络技术】【Kali Linux】Nmap嗅探(二)多设备扫描

上期实验博文&#xff1a;&#xff08;一&#xff09;简单扫描 一、实验环境 本次实验进行Nmap多设备扫描&#xff0c;实验使用 Kali Linux 虚拟机&#xff08;扫描端&#xff09;、Ubuntu 22.04虚拟机&#xff08;被扫描端1&#xff09;、Ubuntu 18.04虚拟机&#xff08;被扫…

金融信贷风控业务详解

前言 Hi&#xff0c;大家好。今天我要根据以往的工作经验做一个全新的业务——金融风控、信贷风控等风控场景。带大家以全新的角度了解风控&#xff0c;包括风控信贷业务讲解、风控决策树、风控决策流、特征工程、三方数据对比和风控系统搭建等一系列知识。 早期的信贷风控做…

代码随想录算法训练营第30天| 51. N皇后、总结

51. N皇后 完成 思路&#xff1a; 如何用回溯法搜索二维棋盘是这道题目和之前不一样的地方&#xff0c;也是题目的难点。 在树形结构中&#xff0c;同层取同一行棋盘的不同列遍历。每递归一次就往下遍历一行。 代码 class Solution {List<List<String>> res n…

platform tree架构下i2c应用实例(HS3003)

目录 概述 1 探究platform tree下的i2c 1.1 platform tree下的i2c驱动 1.2 查看i2c总线下的设备 1.3 使用命令读写设备寄存器 2 认识HS3003 2.1 HS3003特性 2.2 HS3003寄存器 2.2.1 温湿度数据寄存器 2.2.2 参数寄存器 2.2.3 一个参数配置Demo 2.3 温湿度值转换 2.…

FANUC机器人外部远程启动的相关参数设置示例

FANUC机器人外部远程启动的相关参数设置示例 如下图所示,在MENU---设置---选择程序中,设置程序选择模式:RSR(这个根据自己实际使用的自动启动方式来决定,你用RSR选RSR,用PNS就选PNS), 自动运行开始方法:选择UOP,即RSR1-RSR8的启动信号分别对应UI9-UI16, 最后,点击…

一个 SpringBoot 项目能同时处理多少请求?

目录 1 问题分析 2 Demo 3 答案 4 怎么来的&#xff1f; 5 标准答案及影响参数一Tomcat配置 6 影响参数二 Web容器 7 影响参数三 Async 1 问题分析 一个 SpringBoot 项目能同时处理多少请求&#xff1f; 不知道你听到这个问题之后的第一反应是什么&#xff1f; 我大概…

从零开始手写mmo游戏从框架到爆炸(十)— 集成springboot-jpa与用户表

导航&#xff1a;从零开始手写mmo游戏从框架到爆炸&#xff08;零&#xff09;—— 导航-CSDN博客 集成springboot-jpa&#xff0c;不用mybatis框架一个是方便对接不同的数据源。第二个目前规划的游戏内容可能对数据库的依赖不是很大&#xff0c;jpa应该肯定能满足要求了…

redis之布隆过滤

目录 1、redis之布隆过滤 2、布隆过滤器原理 3、布隆过滤器使用步骤 初始化bitmap 添加占坑位 判断是否存在圜 1、redis之布隆过滤 布隆过滤&#xff1a;有一个初值都为0的bit数组和多个哈希函数构成&#xff0c;用来快速判断集合中是否存在某个元素。目的&#xff1a;减…

【STL】list模拟实现

vector模拟实现 一、接口大框架函数声明速览二、结点类的模拟实现1、构造函数 三、迭代器类的模拟实现1、迭代器类存在的意义2、迭代器类的模板参数说明3、构造函数4、运算符的重载&#xff08;前置和后置&#xff09;&#xff08;1&#xff09;前置&#xff08;2&#xff09;后…

Java实现网上药店系统 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 药品类型模块2.3 药品档案模块2.4 药品订单模块2.5 药品收藏模块2.6 药品资讯模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 角色表3.2.2 药品表3.2.3 药品订单表3.2.4 药品收藏表3.2.5 药品留言表…

嵌入式学习之Linux入门篇笔记——18,makefile基本语法(下)

配套视频学习链接&#xff1a;http://【【北京迅为】嵌入式学习之Linux入门篇】 https://www.bilibili.com/video/BV1M7411m7wT/?p4&share_sourcecopy_web&vd_sourcea0ef2c4953d33a9260910aaea45eaec8 1.wildcard 函数 格式&#xff1a;$&#xff08;wildcard PAT…

Oracle11g安装配置详细教程

Oracle Database 11g是一款广泛使用的关系型数据库管理系统&#xff0c;它为企业级的应用提供了强大的数据管理功能。本文将详细介绍如何在Windows环境下安装和配置Oracle 11g。 准备工作 系统要求&#xff1a;确保你的系统满足安装Oracle 11g的最低要求。对于Oracle 11g Rele…

mac电脑flutter环境配置,解决疑难问题

准备工作 首先搭建flutter的环境需要使用到flutter的sdk&#xff0c;可以直接跳去官网下载&#xff1a;Choose your first type of app - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter&#xff0c;下载时要注意你电脑所使用的芯片是Intel的还是苹果的芯片。 下载好的…

C语言之自定义类型:联合和枚举

目录 1. 联合体类型的声明2. 联合体的特点3. 联合体大小的计算联合的一个练习 4. 枚举类型的声明5. 枚举类型的优点6. 枚举类型的使用 1. 联合体类型的声明 像结构体一样&#xff0c;联合体也是由一个或者多个成员构成&#xff0c;这些成员可以不同的类型 但是编译器只为最大…

【JavaWeb】头条新闻项目实现 基本增删改查 分页查询 登录注册校验 业务功能实现 第二期

文章目录 一、为什么使用token口令二、登录注册功能2.1 登录表单提交后端代码&#xff1a; 2.2 根据token获取完整用户信息代码实现&#xff1a; 2.3 注册时用户名占用校验代码实现&#xff1a; 2.4 注册表单提交代码实现&#xff1a; 三、头条首页功能3.1 查询所有头条分类3.2…

HTTP协议笔记

HTTP协议笔记 参考&#xff1a; &#xff08;建议精读&#xff09;HTTP灵魂之问&#xff0c;巩固你的 HTTP 知识体系 《透视 HTTP 协议》——chrono 目录&#xff1a; 1、说说你对HTTP的了解吧。  1. HTTP状态码。  2. HTTP请求头和响应头&#xff0c;其中包括cookie、跨域响…

通过平扫CT实现胰腺癌早筛(平扫CT+AI)

Large-scale pancreatic cancer detection via non-contrast CT and deep learning - PubMed (nih.gov) 实验团队&#xff1a;海军军医大学第一附属医院&#xff08;上海长海医院&#xff09;&#xff0c;放射诊断科曹凯主治医生为共同第一作者&#xff0c;邵成伟、陆建平等教…

第一个 Angular 项目 - 静态页面

第一个 Angular 项目 - 静态页面 之前的笔记&#xff1a; [Angular 基础] - Angular 渲染过程 & 组件的创建 [Angular 基础] - 数据绑定(databinding) [Angular 基础] - 指令(directives) 这是在学完了上面这三个内容后能够完成的项目&#xff0c;目前因为还没有学到数…

【服务器数据恢复】HP EVA虚拟化磁盘阵列数据恢复原理方案

EVA存储结构&原理&#xff1a; EVA是虚拟化存储&#xff0c;在工作过程中&#xff0c;EVA存储中的数据会不断地迁移&#xff0c;再加上运行在EVA上的应用都比较繁重&#xff0c;磁盘负载高&#xff0c;很容易出现故障。EVA是通过大量磁盘的冗余空间和故障后rss冗余磁盘动态…

数据结构第十一天(栈)

目录 前言 概述 源码&#xff1a; 主函数&#xff1a; 运行结果&#xff1a; ​编辑 前言 今天简单的实现了栈&#xff0c;主要还是指针操作&#xff0c;soeasy! 友友们如果想存储其他内容&#xff0c;只需修改结构体中的内容即可。 哈哈&#xff0c;要是感觉不错&…