2023-02-24
Nodejs
00

1. 创建服务器

什么是 Web 服务器?

  • 当应用程序(客户端)需要某个资源时,可以向一台服务器,通过 HTTP 请求获取到这个资源
  • 提供资源的这个服务器,就是一个 Web 服务器

image.png

目前有很多开源的 Web 服务器:NginxApache(静态)Apache Tomcat(静态、动态)Node.js

Node 中,提供 web 服务器的资源返回给浏览器,主要是通过 http 模块。

我们先简单对它做一个使用:

js
const http = require("http"); const HTTP_PORT = 9000; const server = http.createServer((req, res) => { res.end("Hello World"); }); server.listen(HTTP_PORT, () => { console.log(`服务器在${HTTP_PORT}启动`); });

此时我们在浏览器中输入 localhost:9000,就会出现 Hello World

image.png

解释上面这段代码:

  1. 通过 http 模块的 createServer 方法创建了一个服务器对象,它的底层其实是直接使用 new Server 创建对象的。

    image.png

    那么当然,我们也可以自己来创建这个对象:

    js
    const server = new http.Server((req, res) => { res.end("Hello World"); }); server.listen(HTTP_PORT, () => { console.log(`服务器在${HTTP_PORT}启动`); });
  2. 创建 Server 时会传入一个回调函数,这个回调函数在被调用时会传入两个参数:

    1. reqrequest 请求对象,包含请求相关的信息;
    2. resresponse 响应对象,包含我们要发送给客户端的信息;
  3. Server 通过 listen 方法来开启服务器,并且在某一个主机的端口上监听网络请求

    也就是当我们通过 ip:port 的方式发送到我们监听的 Web 服务器上时,我们就可以对其进行相关的处理;

    listen 函数有三个参数:

    1. 端口 port:可以不传,系统会默认分配端

    2. 主机 host:通常可以传入 localhostip地址127.0.0.1、或者 ip地址0.0.0.0,默认是 0.0.0.0

      1. localhost:本质上是一个域名,通常情况下会被解析成 127.0.0.1

      2. 127.0.0.1回环地址(Loop Back Address),表达的意思其实是我们主机自己发出去的包,直接被自己接收;

        • 正常的数据包会经过 应用层 - 传输层 - 网络层 - 数据链路层 - 物理层
        • 而回环地址,是在网络层直接就被获取到了,是不会经常数据链路层物理层的;
        • 比如我们监听 127.0.0.1 时,在同一个网段下的主机中,通过 ip地址 是不能访问的;
      3. 0.0.0.0

        • 监听 IPV4 上所有的地址,再根据端口找到不同的应用程序;
        • 比如我们监听 0.0.0.0 时,在同一个网段下的主机中,通过 ip 地址是可以访问的;
    3. 回调函数:服务器启动成功时的回调函数;

2023-02-24
Nodejs
00

1. Buffer 缓冲区

我们会发现,对于前端开发来说,通常很少会和二进制直接打交道,但是对于服务器端为了做很多的功能,我们必须直接去操作其二进制的数据;

所以 Node 为了可以方便开发者完成更多功能,提供给了我们一个 Buffer类用来创建一个专门存放二进制数据的缓存区,并且它是全局的。

我们可以将 Buffer 看成是一个存储二进制的数组,这个数组中的每一项,可以保存 8 位二进制:0000 0000

1. Buffer 和字符串

Buffer 相当于是一个字节的数组,数组中的每一项对应一个字节的大小

如果我们希望将一个字符串放入到 Buffer 中,是怎么样的过程呢?

js
const buffer = new Buffer("hello"); console.log(buffer);

打印结果如下:

image.png

可以看到打印出的 Buffer 对象包含了五个 由两位十六进制组成的数字。而我们知道 2 位十六进制正好对应 8 位二进制也就是一个字节

而如果你去查询 ASCII 表的话会发现,这五个十六进制数正好对应着英文字母的 h e l l o

image.png

也就是说,我们可以得出结论:Buffer 存储字符串时默认是以 ASCII 将字符串编码存储的

1.2 Buffer 与中文

Buffer 默认是以 utf-8 为默认编码存储中文的

在上面一小节的例子中,我们使用 new Buffer() 创建了一个 Buffer 对象,事实上由于安全性和可用性的问题,Node 已经废弃了这种方法,推荐使用 Buffer.alloc()Buffer.allocUnsafe() 或者 Buffer.from() 这三种方法创建 Buffer 对象

接下来我们试着用 Buffer 存储中文:

js
const buf = Buffer.from("你好"); console.log(buf);

打印结果如下:

image.png

我们知道在 UTF-8 中,一个中文等于三个字节。而在上面的打印结果也能看出 “你好” 两个字正好存储了六个两位十六进制的数字,证实了我们的结论。

乱码的问题:

  1. 一般乱码的问题都是因为编码与解码使用了不同的方法而导致的。
  2. Buffer.from() 方法中,我们还可以添加第二个参数来规定使用哪种编码方式
js
const fs = require("fs"); const buf = Buffer.from("你好", "utf16le"); console.log(buf.toString("utf16le")); console.log(buf.toString("utf8"));

打印结果:

image.png

可以看到,同时以 utf-16 解码打印出来没有出现乱码,而以 utf-8 解码打印出来出现了乱码。

1.3 Buffer 的其他创建方式

关于 Buffer 的创建方式还有很多,见下图

image.png

这里主要再讲一下 alloc,如果有学习 c 语言的应该是很熟悉的。它的意思是 承认、同意。Buffer.alloc 的作用为向内存申请一个多长的 Buffer,里面的默认数据是 00

js
const buf = Buffer.alloc(8); console.log(buf);

打印结果如下

image.png

我们也可以对其进行操作

js
buf[0] = "w".charCodeAt(); buf[1] = 100; buf[2] = 0x66; console.log(buf); // <Buffer 77 64 66 00 00 00 00 00> console.log(buf[0]); // 119 console.log(buf[2].toString()); // 102

1.4 Buffer 和文件读取

在上一章 fs 模块中介绍中,我们提到了 readFile 的回调是一个 Buffer,现在大家应该也能理解了吧

  1. 文本的读取
js
const fs = require("fs"); fs.readFile("./test.txt", (err, data) => { console.log(data); // <Buffer 48 65 6c 6c 6f 20 57 6f 72 6c 64> console.log(data.toString()); // Hello World });
  1. 图片的读取
js
const fs = require("fs"); fs.readFile("./image.png", (err, data) => { console.log(data); // <Buffer 89 50 4e 47 0d 0a 1a 0a 00 00 ... 1878012 more bytes> });
2023-02-23
Nodejs
00

前言

对于任何一个为服务端服务的语言或者框架来说,通常都会有自己的文件系统:

  1. 因为服务器需要将各种数据、文件等放置到不同的地方;
  2. 比如用户数据可能大多数都是放到数据库的
  3. 比如某些配置文件或者用户资源(图片、音视频)都是以文件的形式存在操作系统上

Node 也有自己的文件系统操作模块。就是 fs(File System)

借助于 Node 帮我们封装的文件系统,我们可以在任何的操作系统(window、Mac OS、Linus)上面直接去操作文件。这也是 Node 可以开发服务器的一大原因,也是它可以成为前端自动化脚本等热门工具的原因。

Node 文件系统的 API 非常多,这些 API大多数都提供了三种操作方式

  1. 同步操作文件:代码会被阻塞,不会继续执行;
  2. 异步回调函数操作文件:代码不会被阻塞,需要传入回调函数,当返回结果时,回调函数被执行;
  3. 异步 Promise 操作文件:代码不会被阻塞,通过 fs.promises 调用方法操作,会返回一个 Promise,可以通过 thencatcth 进行处理

本章我们呢会介绍最常用的几种 API。贴一下 文档地址,没介绍到的就去查文档吧。

2023-02-23
Leetcode
00

前言

拒绝摆烂ヾ(◍°∇°◍)ノ゙

从今天开始(2023/02/12),定一个小目标,先刷个 300Leetcode 题目(之前刷的不计入)。

当然作为一个小前端,我选择的语言是 TS,而且刷的题目的难度会偏中等一些,大概按照 简单3 中等6 困难1 这样的题型分布吧。嗯,目前是这么打算的。

本题 Github 地址:因为比较喜欢 vscode 的界面,而且方便调试,所以 AC 完就顺便提到 github 了,也算做一个记录吧。

本篇的题目是这个系列的第

  1. NO.2615. 三数之和
  2. NO.2716. 最接近的三数之和
  3. NO.2818. 四数之和

1. 认识排序算法

排序算法就是研究如何对一个集合进行高效排序的算法,也是在面试时非常常见的面试题型之一。

下面是维基百科堆排序算法的解释:

在计算机科学与数学中,一个排序算法(Sorting algorithm) 是一种能将一串资料依照特定排序方式排列的算法。

在计算机科学所使用的排序算法通常依以下标准分类:

  • 计算的时间复杂度:使用大 O 表示法,也可以实际测试消耗的时间;
  • 内存使用量:比如外部排序,使用磁盘来存储排序的数据
  • 稳定性:稳定排序算法会让原本相等键值的记录维持相对次序
  • 排序的方法:插入、交换、选择、合并等等

常见的排序算法

  1. 冒泡排序
  2. 选择排序
  3. 插入排序
  4. 归并排序
  5. 快速排序
  6. 堆排序
  7. ...