XSS

跨站脚本攻击(XSS,Cross - Site Scripting) 攻击者通过在目标网站中注入恶意脚本,来获取用户的敏感信息、执行恶意操作等。这些恶意脚本通常是 JavaScript

本质上就是在任何前端js可能读取的地方插入恶意脚本

整体过程

攻击者提交恶意代码 -> 浏览器执行恶意代码

反射型XSS

示例:一个简单的搜索功能,用户在搜索框输入内容后,服务器将用户输入的内容直接在页面上显示。攻击者构造一个类似 http://example.com/search?q=<script>alert('XSS')</script> 的 URL,当用户点击这个链接,就会弹出一个警告框显示 “XSS”。

阅读全文 »

先开个坑,准备下Web3相关的学习

学习路线

WEEK 1: 区块链的基础知识

  • 密码学基础
  • 区块链基础
  • 相关金融知识
  • 学习比特币底层技术
  • 学习以太坊原理

Hexo介绍

Hexo是一款基于Node.js的开源静态博客框架,用于快速、简单且高效地搭建静态博客网站。本质上是一个静态网站生成器,新增文章只需要编辑md文件,通过运行命令再生成像html的静态文件。

环境搭建

1
2
3
4
5
6
7
8
9
10
11
# 全局安装hexo脚手架
npm install -g hexo-cli

# 创建一blog项目
hexo init blog

# 进入项目
cd blog

# 安装依赖包
npm install

其他操作

1
2
# 右键 Git Bush,用户项目自动化部署
npm install hexo-deployer-git --save

项目预览

1
2
3
4
5
6
7
8
# 清理旧的静态文件
hexo clean

# 生成静态文件
hexo g

# 运行预览项目
hexo s
阅读全文 »

记录面试中遇到一些比较有意思的场景题

虚拟滚动是如何去实现的(长列表,大表格)

1、监听滚轮事件/触摸事件,记录列表的总偏移量。
2、根据总偏移量计算列表的可视元素起始索引。
3、从起始索引渲染元素至视口底部。
4、当总偏移量更新时,重新渲染可视元素列表。
5、为可视元素列表前后加入缓冲元素。
6、在滚动量比较小时,直接修改可视元素列表的偏移量。
7、在滚动量比较大时(比如拖动滚动条),会重新渲染整个列表。
事件节流。

包管理器

Pnpm是怎么解决幽灵依赖的

hard link + symbolic link

如何确定一个项目用的包管理器版本:enigne字段
1
2
3
4
"engines": {
"node": ">=14.0.0",
"npm": ">=7.0.0" // 项目要求的 npm 最低版本
}
如何避免业务项目被发到npm上
在 package.json 中添加 private 字段

在项目的 package.json 文件中添加 private: true 字段,这是最直接的方式。当 private 为 true 时,npm 会拒绝发布该项目。

使用 .npmignore 或 .gitignore 文件

将项目中的所有文件添加到忽略列表,确保没有文件被发布。.npmignore 会覆盖 .gitignore 的规则。

设置预发布钩子

在 package.json 中添加 prepublishOnly 脚本,使其在发布前失败:

使用 .npmrc 文件锁定发布源

在项目根目录创建 .npmrc 文件,设置为私有源或无效源:

阅读全文 »

React 整体渲染流程

为什么要有React Fiber?

见:React Fiber的意义

jsx、ReactElement、虚拟DOM 、Fiber的关系

树里的一个 React 元素(ReactElement)对应一个 Fiber,一个 Fiber 也对应树里的一个元素。
见:JSX、ReactElement、FiberNode、DomElement

常见的生命周期函数都是在哪些渲染阶段被调用

见:常见的生命周期函数都是在哪些渲染阶段被调用

diff算法的过程

单节点和多节点Diff:Diff算法

fiberRootNode与rootFiber的结构

fiberRootNode 是“整棵应用的根管理对象(Root 容器)”,而 rootFiber 是“Fiber 树里的第一个 Fiber 节点(HostRootFiber)”。

见:FiberRootNode存储的信息Fiber Node存储的信息

setState后React都做了什么

见:从一次 useState 的 setState 开始后发生了什么

React Scheduler为什么一定要把任务包在宏任务里执行?

思考能否使用如下方案:直接同步执行,限制好执行时间(5ms)
答案是,不行。

Scheduler本质上做的不仅仅是分片,还要把控制权交还给浏览器

  • 纯同步执行 + 自己看时间,理论上可以“分段”,但本质上你还是在当前调用栈里,浏览器拿不到控制权,不能及时处理输入/渲染。
  • React 需要的是协作式调度:做一小段 -> 让出线程 -> 下轮再继续。这就必须依赖异步边界(MessageChannel/setTimeout 这种 task 机制)。

React Scheduler 为什么不用requestIdleCallback实现

  1. 兼容性差 Safari 并不支持 https://caniuse.com
  2. 控制精细度 React 要根据组件优先级、更新的紧急程度等信息,更精确地安排渲染的工作
  3. 执行时机requestIdleCallback(callback) 回调函数的执行间隔是 50ms(W3C规定),也就是 20FPS,1秒内执行20次,间隔较长。
  4. 差异性 每个浏览器实现该API的方式不同,导致执行时机有差异有的快有的慢
requestIdleCallback的替代方案?

MessageChannel

选择 MessageChannel 的原因,是首先异步得是个宏任务,因为宏任务中会在下次事件循环中执行,不会阻塞当前页面的更新。MessageChannel 是一个宏任务。

没选常见的 setTimeout,是因为MessageChannel较快执行,在 0~1ms 内触发,像 setTimeout 即便设置 timeout 为 0 还是需要4~5ms。相同时间下,MessageChannel 能够完成更多的任务。

并发渲染

支持 new concurrent renderer(并发模式的渲染)

  • 并发模式不是一个功能,而是一个底层设计。
  • 它可以帮助应用保持响应,根据用户的设备性能和网速进行调整。
  • 通过渲染可中断来修复阻塞渲染机制。在 concurrent 模式中,React 可以同时更新多个状态。
  • 区别就是使同步不可中断更新变成了异步可中断更新。
  • useDeferredValue 和 startTransition 用来标记一次非紧急更新。

starTransition:用于标记非紧急的更新,用 starTransition 包裹起来就是告诉 React,这部分代码渲染的优先级不高,可以优先处理其它更重要的渲染。

useTransition:除了能提供 startTransition 以外,还能提供一个变量来跟踪当前渲染的执行状态。

React 的并发机制允许 React 在渲染过程中根据任务的优先级进行调度和中断,从而确保高优先级的更新能够及时渲染,而不会被低优先级的任务阻塞。

并发机制的工作原理

时间分片(Time Slicing): React 将渲染任务拆分为多个小片段,每个片段在主线程空闲时执行。这使得浏览器可以在渲染过程中处理用户输入和其他高优先级任务,避免长时间的渲染阻塞用户交互。

优先级调度(Priority Scheduling): React 为不同的更新分配不同的优先级。高优先级的更新(如用户输入)会被优先处理,而低优先级的更新(如数据预加载)可以在空闲时处理。

可中断渲染(Interruptible Rendering): 在并发模式下,React 可以中断当前的渲染任务,处理更高优先级的任务,然后再恢复之前的渲染。这确保了应用在长时间渲染过程中仍能保持响应性。

并发机制的优势
  • 提升响应性: 通过优先处理高优先级任务,React 能够更快地响应用户输入,提升用户体验。
  • 优化性能: 将渲染任务拆分为小片段,避免长时间的渲染阻塞,提升应用的整体性能。
  • 更好的资源利用: 在主线程空闲时处理低优先级任务,充分利用系统资源。
如何启用并发模式

要在 React 应用中启用并发模式,需要使用 createRoot API:

1
2
3
4
5
6
7
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'

const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(<App />)

在并发模式下,React 会自动根据任务的优先级进行调度和渲染。

useTransition 本质:把一部分更新标记到“过渡 lane(低优先级车道)”,让紧急更新(输入、点击)先渲染,过渡更新可以被打断、延后。

useDeferredValue 本质:把某个值的更新“映射”到过渡 lane,上游状态先变,依赖这个值的重渲染滞后一点,起到“值级别的 useTransition”效果。

什么是lane模型

见:Lane模型

状态更新与批量更新机制

同一个上下文中的setState会被合并

React 17以及之前:

  • onClick 里的多个 setState 会被批处理
  • setTimeout / Promise.then 里的更新通常不会自动批处理(会各自触发)

React 18(createRoot)

引入了更广泛的自动批处理:

  • React 事件里批处理
  • setTimeout、Promise、原生事件回调里也会自动批处理(多数场景)

setState 是同步还是异步的

useState怎么实现的第一次拿初始状态,后续拿之前状态

判断挂载还是Update,如果是Update阶段根据BaseState和Update对象计算出最新的state

useState等hooks为什么不能写在函数组件外面

因为hook要挂到当前Fiber上

React18 的自动批处理与 flushSync

  • 在 react17 中,只有 React 事件会进行批处理,原生 js 事件、promise,setTimeout、setInterval 不会。
  • react18 中,将所有事件都进行批处理,即多次 setState 会被合并为 1 次执行,提高了性能。

flushSync:退出批量更新,强制立即刷新视图。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import React,{useState} from "react"
import {flushSync} from "react-dom"

const App=()=>{
const [count,setCount]=useState(0)
const [count2,setCount2]=useState(0)

return (
<div className="App">
<button onClick=(()=>{
// 第一次更新
flushSync(()=>{
setCount(count=>count+1)
})
// 第二次更新
flushSync(()=>{
setCount2(count2=>count2+1)
})
})>点击</button>
<span>count:{count}</span>
<span>count2:{count2}</span>
</div>
)
}
export default App

其他 React18/19 新特性

  • 放弃对 IE 浏览器的支持:react18/19 引入的新特性全部基于现代浏览器,如需支持需要退回到 react17 版本。
  • Suspense 不再需要 fallback 捕获。
  • 支持 useId:在服务器和客户端生成相同的唯一一个 id,避免 hydrating 的不兼容。
  • useSyncExternalStore:用于解决外部数据撕裂问题。
  • useInsertionEffect:这个 hooks 只建议在 css in js 库中使用,这个 hooks 执行时机在 DOM 生成之后,useLayoutEffect 执行之前,无法访问 DOM 节点引用,一般用于提前注入脚本。

React Hooks

见:Hooks

封装自定义 Hooks

实现 useTimeout hook

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// callback 回调函数, delay 延迟时间
function useTimeout(callback, delay) {
const memorizeCallback = useRef();

useEffect(() => {
memorizeCallback.current = callback;
}, [callback]);

useEffect(() => {
if (delay !== null) {
const timer = setTimeout(() => {
memorizeCallback.current();
}, delay);
return () => {
clearTimeout(timer);
};
}
}, [delay]);
};

实现一个 dom 可见性的 hook

实现的一个关键点是 Ref 的更新在 useEffect 执行前

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import { useEffect, useState, useRef } from "react";
const useInView = (
options = {
root: null,
rootMargin: "0px 0px",
threshold: 1,
},
triggerOnce = false, // 是否只触发一次
) => {
const [inView, setInView] = useState(false);
const targetRef = useRef(null);

useEffect(() => {
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
setInView(true);
if (triggerOnce) {
// 触发一次后结束监听
observer.unobserve(entry.target);
}
} else {
setInView(false);
}
});
}, options);

if (targetRef.current) {
// 开始监听
observer.observe(targetRef.current);
}

return () => {
if (targetRef.current) {
// 组件卸载时结束监听
observer.unobserve(targetRef.current);
}
};
}, [options, triggerOnce]);

return [targetRef, inView];
};

export default useInView;

状态管理相关

React Hooks 如何实现类似 Redux 的状态管理

useContext + useReducer。

Redux 性能问题

Redux vs Mobx

Redux RTX

ImmerJS

React Router 路由模式与实现原理

几种模式

<BrowserRouter> /<HashRouter>

  • hash 模式(<HashRouter>):在 url 后面加上 #,如 http://127.0.0.1:5500/home/#/page1
  • history 模式(<BrowserRouter>):允许操作浏览器的曾经在标签页或者框架里访问的会话历史记录

hash 模式

URL 示例:https://example.com/#/about、https://example.com/#/users/123

history模式

URL 示例:https://example.com/about、https://example.com/users/123

history模式最重要的是部署需要配合Nginx,所有路由都返回 index.html

事件循环

见:浏览器架构和事件循环

this相关

见:this指向

原型和原型链

见:JS原型和原型链

JS二进制相关

见:JS二进制:File、Blob、FileReader、ArrayBuffer、Base64

执行上下文、作用域链

见:JavaScript执行上下文

JS相关API

见:JS相关API

其他

let、const的区别

  • 块级作用域
  • 重复声明变量会报错
  • 不能在声明前访问
阅读全文 »

Webpack 是什么

webpack 是一种前端资源构建工具,一个静态模块打包器(module bundler)。
在webpack 看来, 前端的所有资源文件(js/json/css/img/less/…)都会作为模块处理。
它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)。

Webpack 五个核心概念

Entry

入口(Entry):指示 webpack 以哪个文件为入口起点开始打包,分析构建内部依赖图。

Output

输出(Output):指示 webpack 打包后的资源 bundles 输出到哪里去,以及如何命名。

Loader

Loader:让 webpack 能够去处理那些非 JS 的文件,比如样式文件、图片文件(webpack 自身只理解
JS)

Plugins

插件(Plugins):可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,
一直到重新定义环境中的变量等。

阅读全文 »
0%