likes
comments
collection
share

21天筑基期--Node.js+工程化系列

作者站长头像
站长
· 阅读数 14

Node.js

官方文档

如何实现jwt鉴权机制

JWT(JSON Web Token),本质就是一个字符串书写规范,如下图,作用是用来在用户和服务器之间传递安全可靠的信息 Token的使用分成了两部分:

  • 生成token:登录成功的时候,颁发token
  • 验证token:访问某些资源或者接口时,验证token

对中间件概念

中间件(Middleware)是介于应用系统和系统软件之间的一类软件,它使用系统软件所提供的基础服务(功能),衔接网络上应用系统的各个部分或不同的应用,能够达到资源共享、功能共享的目的

例如在expresskoaweb框架中,中间件的本质为一个回调函数,参数包含请求对象、响应对象和执行下一个中间件的函数

中间件模型不同:express 的中间件模型为线型,而 koa 的为U型(洋葱模型)。

Nodejs中的事件循环机制

  • timers阶段:这个阶段执行timer(setTimeout、setInterval)的回调
  • 定时器检测阶段(timers):本阶段执行 timer 的回调,即 setTimeout、setInterval 里面的回调函数
  • I/O事件回调阶段(I/O callbacks):执行延迟到下一个循环迭代的 I/O 回调,即上一轮循环中未被执行的一些I/O回调
  • 闲置阶段(idle, prepare):仅系统内部使用
  • 轮询阶段(poll):检索新的 I/O 事件;执行与 I/O 相关的回调(几乎所有情况下,除了关闭的回调函数,那些由计时器和 setImmediate() 调度的之外),其余情况 node 将在适当的时候在此阻塞
  • 检查阶段(check):setImmediate() 回调函数在这里执行
  • 关闭事件回调阶段(close callback):一些关闭的回调函数,如:socket.on('close', ...)

说说什么是进程?什么是线程?

进程

进程是一种抽象的概念,从来没有统一的标准定义看,一般由程序、数据集合和进程控制块三部分组成:

  • 程序用于描述进程要完成的功能,是控制进程执行的指令集
  • 数据集合是程序在执行时所需要的数据和工作区
  • 程序控制块,包含进程的描述信息和控制信息,是进程存在的唯一标志

线程

线程(thread)是操作系统能够进行运算调度的最小单位,其是进程中的一个执行任务(控制单元),负责当前进程中程序的执行

一个进程至少有一个线程,一个进程可以运行多个线程,这些线程共享同一块内存,线程之间可以共享对象、资源,如果有冲突或需要协同,还可以随时沟通以解决冲突或保持同步

区别

  • 本质区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位
  • 在开销方面:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小
  • 所处环境:在操作系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行(通过CPU调度,在每个时间片中只有一个线程执行)
  • 内存分配方面:系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,除了CPU外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源
  • 包含关系:没有线程的进程可以看做是单线程的,如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程

举个例子:进程=火车,线程=车厢

  • 线程在进程下行进(单纯的车厢无法运行)
  • 一个进程可以包含多个线程(一辆火车可以有多个车厢)
  • 不同进程间数据很难共享(一辆火车上的乘客很难换到另外一辆火车,比如站点换乘)
  • 同一进程下不同线程间数据很易共享(A车厢换到B车厢很容易)
  • 进程要比线程消耗更多的计算机资源(采用多列火车相比多个车厢更耗资源)
  • 进程间不会相互影响,一个线程挂掉将导致整个进程挂掉(一列火车不会影响到另外一列火车,但是如果一列火车上中间的一节车厢着火了,将影响到所有车厢)

Node 中的 Buffer 的理解

Node应用中,需要处理网络协议、操作数据库、处理图片、接收上传文件等,在网络流和文件的操作中,要处理大量二进制数据,而Buffer就是在内存中开辟一片区域(初次初始化为8KB),用来存放二进制数据

  1. 网络通信:可以使用Buffer.from()方法将字符串转换为二进制数据,然后使用net模块进行网络通信:
const net = require('net');

const client = net.createConnection({ port: 8080 }, () => {
  // 将字符串转换为二进制数据
  const data = Buffer.from('Hello, world!', 'utf8');

  // 发送数据
  client.write(data);
});
  1. 文件操作,用Buffer来存储文件数据:

const fs = require('fs');

// 读取文件,并将数据存储到 Buffer 对象中
const data = fs.readFileSync('/path/to/file');

// 处理数据
// ...
  1. 加密解密,例如,可以使用 crypto 模块创建加密解密算法需要的二进制数据:
const crypto = require('crypto');

// 创建加密解密算法需要的二进制数据
const key = Buffer.from('mysecretkey', 'utf8');
const iv = Buffer.alloc(16);

// 创建加密解密算法对象
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);

// 加密数据
const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
  1. 图像处理:

Node 中的 Stream 的理解

Stream是一种处理流式数据的抽象接口,用于读取、写入、转换和操作数据流。它是一个基于事件的 API,可以让我们以高效、低延迟的方式处理大型数据集。

说直白点就是基于Stream封装的API,性能更好。

比如读取文件,使用流我们可以一点一点来读取文件,每次只读取或写入文件的一小部分数据块,而不是一次性将整个文件读取或写入到内存中或磁盘中,这样做能够降低内存占用。

express.js 和 koa.js 的区别是什么?

  1. 中间件模型不同:express 的中间件模型为线型,而 koa 的为U型(洋葱模型)。
  1. 对异步的处理不同:express 通过回调函数处理异步,而 koa 通过generator 和 async/await 使用同步的写法来处理异步,后者更易维护,但彼时 Node.js 对 async 的兼容性和优化并不够好,所以没有流行起来。
  1. 功能不同:express 包含路由、渲染等特性,而 koa 只有 http 模块。

总得来说,express 功能多一点,写法烂一点,兼容性好一点,所以当时更流行。虽然现在 Node.js 已经对 await 支持得很好了,但是 koa 已经错过了风口。

不过 express 和 koa 的作者都是 TJ 大神。

工程化

说一说前端性能优化手段

浅谈web前端性能优化 - 掘金 (juejin.cn)

webpack的构建流程

21天筑基期--Node.js+工程化系列

21天筑基期--Node.js+工程化系列

常见 loader 和 plugin 有哪些?二者的区别是什么?

常见 loader

在 webpack 文档里写了:

Loaders | webpack 你可以记住:

  1. babel-loader 把 JS/TS 变成 JS
  1. ts-loader 把 TS 变成 JS,并提示类型错误
  1. markdown-loader 把 markdown 变成 html
  1. html-loader 把 html 变成 JS 字符串
  1. sass-loader 把 SASS/SCSS 变成 CSS
  1. css-loader 把 CSS 变成 JS 字符串
  1. style-loader 把 JS 字符串变成 style 标签
  1. postcss-loader 把 CSS 变成更优化的 CSS
  1. vue-loader 把单文件组件(SFC)变成 JS 模块
  1. thread-loader 用于多进程打包

常见 plugin

也在 webpack 文档里写了:

Plugins | webpack 你可以记住这些:

  1. html-webpack-plugin 用于创建 HTML 页面并自动引入 JS 和 CSS
  1. clean-webpack-plugin 用于清理之前打包的残余文件
  1. mini-css-extract-plugin 用于将 JS 中的 CSS 抽离成单独的 CSS 文件
  1. SplitChunksPlugin 用于代码分包(Code Split)
  1. DllPlugin + DllReferencePlugin 用于避免大依赖被频繁重新打包,大幅降低打包时间

    webpack使用-详解DllPlugin 3. eslint-webpack-plugin 用于检查代码中的错误

  1. DefinePlugin 用于在 webpack config 里添加全局变量
  1. copy-webpack-plugin 用于拷贝静态文件到 dist

二者的区别

  • loader 是文件加载器(这句废话很重要)

    • 功能:能够对文件进行编译、优化、混淆(压缩)等,比如 babel-loader / vue-loader
    • 运行时机:在创建最终产物之前运行
  • plugin 是 webpack 插件(这句废话也很重要)

    • 功能:能实现更多功能,比如定义全局变量、Code Split、加速编译等
    • 运行时机:在整个打包过程(以及前后)都能运行

webpack proxy工作原理?为什么能解决跨域

webpack proxy,即webpack提供的代理服务

基本行为就是接收客户端发送的请求后转发给其他服务器

其目的是为了便于开发者在开发模式下解决跨域问题(浏览器安全策略限制)

想要实现代理首先需要一个中间服务器,webpack中提供服务器的工具为webpack-dev-server

跨域问题

关于配置方面,在webpack配置对象属性中通过devServer属性提供,如下:

module.exports = {
  //...
  devServer: {
    proxy: {
      '/api': {
        target: 'http://xiedaimala.com',
        changeOrigin: true,
      },
    },
  },
};

devServetr里面proxy则是关于代理的配置,该属性为对象的形式,对象中每一个属性就是一个代理的规则匹配

属性的名称是需要被代理的请求路径前缀,一般为了辨别都会设置前缀为 /api,值为对应的代理匹配规则,对应如下:

  • target:表示的是代理到的目标地址
  • pathRewrite:默认情况下,我们的 /api-hy 也会被写入到URL中,如果希望删除,可以使用pathRewrite
  • secure:默认情况下不接收转发到https的服务器上,如果希望支持,可以设置为false
  • changeOrigin:它表示是否更新代理后请求的 headers 中host地址

如何提高 webpack 构建速度?

  1. 使用 DllPlugin 将不常变化的代码提前打包,并复用,如 vue、react
  1. 使用 thread-loader 或 HappyPack(过时)进行多线程打包
  1. 处于开发环境时,在 webpack config 中将 cache 设为 true,也可用 cache-loader(过时)
  1. 处于生产环境时,关闭不必要的环节,比如可以关闭 source map
  1. 网传的 HardSourceWebpackPlugin 已经一年多没更新了,谨慎使用

vite

构建工具的高阶封装, 内部使用的其它的构建工具, 最核心的是 Rollup, 与框架无关

  • 开发时效率极高
  • 开箱即用, 功能完备
  • 社区丰富, 兼容 rollup
  • 超高速热重载
  • 预设应用和类库打包模式
  • 前端类库无关

webpack 与 vite 的区别是什么?

vite 相比webpack的优缺点。 - 掘金 (juejin.cn)

  1. 开发环境区别

    1. vite 自己实现 server,不对代码打包,充分利用浏览器对 <script type=module> 的支持

      1. 假设 main.js 引入了 vue
      1. 该 server 会把 import { createApp } from 'vue' 改为 import { createApp } from "/node_modules/.vite/vue.js" 这样浏览器就知道去哪里找 vue.js 了
    1. webpack-dev-server 常使用 babel-loader 基于内存打包,比 vite 慢很多很多很多

      1. 该 server 会把 vue.js 的代码(递归地)打包进 main.js
  1. 生产环境区别

    1. vite 使用 *rollup *+ *esbuild *来打包 JS 代码
    1. *webpack *使用 *babel *来打包 JS 代码,比 esbuild 慢很多很多很多

      1. webpack 能使用 esbuild 吗?可以,你要自己配置(很麻烦)。
  1. 文件处理时机

    1. vite 只会在你请求某个文件的时候处理该文件
    1. webpack 会提前打包好 main.js,等你请求的时候直接输出打包好的 JS 给你

目前已知 vite 的缺点有:

  1. 热更新常常失败,原因不清楚
  1. 有些功能 rollup 不支持,需要自己写 rollup 插件
  1. 不支持非现代浏览器