当前位置: 首页 > news >正文

【常考前端面试题总结】---2025

React

fiber架构

1.为什么会出现 React fiber 架构?

React 15 Stack Reconciler 是通过递归更新子组件 。由于递归执行,所以更新一旦开始,中途就无法中断。当层级很深时,递归更新时间超过了 16ms,用户交互就会卡顿。对于特别庞大的DOM树来说,reconciliation过程会很长(x00ms),在这期间,主线程是被 js 占用的,因此任何交互、布局、渲染都会停止,给用户的感觉就是页面被卡住了。网友测试使用React V15,当DOM节点数量达到100000时, 加载页面时间竟然要 7 秒。

总结原因:
(1) 长时间阻塞主线程
(2) 无法分配优先级 高优先级任务(如用户输入)无法抢占低优先级任务(如后台数据更新)。
(3) 缺乏灵活的错误恢复
同步渲染中,如果某一部分出错,整个渲染过程都会中断,无法优雅地处理错误。

2.Fiber是什么?

官方的一句话解释是“React Fiber是对核心算法的一次重新实现” 。我觉得是一种协调。

Fiber架构 = Fiber节点 + Fiber调度算法

1.把一个耗时长的任务分解为一个个的工作单元。 在执行工作单元之前,由浏览器判断是否有空余时间执行,有时间就执行工作单元,执行完成后,继续判断是否还有空闲时间。没有时间就终止执行让浏览器执行其他任务(如 GUI 线程等)。等到下一帧执行时判断是否有空余时间,有时间就从终止的地方继续执行工作单元,一直重复到任务结束。
2.要让终止的任务恢复执行,就必须知道下一工作单元对应那一个。所以要实现工作单元的连接,就要使用链表,在每个工作单元中保存下一个工作单元的指针,就能恢复任务的执行。
3.要知道每一帧的空闲时间,就需要使用 requestIdleCallback Api。传入回调函数,回调函数接收一个参数(剩余时间),如果有剩余时间,那么就执行工作单元,如果时间不足了,则继续requestIdleCallback,等到下一帧继续判断。

总结核心概念
(1)Fiber节点 :Fiber 是 React 中用来表示虚拟 DOM 的一种数据结构。每个 Fiber 节点对应一个 React 元素或组件,Fiber 节点形成一棵链表树,通过 child、sibling 和 return 指针连接起来。
(2)时间切片 :Fiber 允许将渲染任务分成多个小的单元,每次处理一部分任务。如果有更高优先级的任务(如用户输入事件)出现,可以暂停当前任务,先处理高优任务。
(3)** 双缓冲机制** : Current Fiber Tree:表示当前屏幕上渲染的内容。Work-in-progress Fiber Tree:表示正在构建的新 Fiber 树。
(4)优先级调度 :引入了调度器(Scheduler),根据任务的类型和优先级分配资源。高优先级:用户输入(如点击、键盘事件)。中优先级:动画、过渡效果。低优先级:后台数据加载或非关键渲染。

Fiber优点:

  • 可中断更新:长任务被分解成小任务,减少主线程阻塞,提升用户体验。
  • **优先级调度:**任务可以根据优先级被调度和重新安排。
  • **增量渲染:**允许逐步构建UI,避免界面冻结。
  • **增强错误边界:**错误可以被捕获,避免整棵树崩溃。
  • **支持未来特性:**如 Concurrent Mode 和Suspense。

Fiber工作流程?

  1. 使用 Fiber 节点, 来代替虚拟 DOM 原来的结构。
  2. 通过 ReactDOM.render() 和 setState 把待更新的任务会先放入队列中, 然后通过 requestIdleCallback 请求浏览器调度。
  3. 现在浏览器有空闲或者超时了就会调用 performWork 来执行任务:
  4. nextUnitOfWork 下一个工作单元是 Fiber 结构,所以终止了之后也能恢复继续执行。
  5. 渲染阶段, 协调阶段完成后生成了 WorkInProgress Tree,在有修改的 Fiber 节点中都有一个标签,在 Renderer 阶段循环 WorkInProgress Tree 进行修改节点然后渲染到页面上。

Fiber 的渲染分为两个阶段:
(1) 阶段 1:Reconciliation(调和阶段)
对比新旧 Fiber 树,找出需要更新的部分。此阶段是增量化的,可以被打断。React 根据优先级调度任务,并在空闲时间继续完成调和。
(2) 阶段 2:Commit(提交阶段)
将计算出的更新应用到真实的 DOM。此阶段是同步的,一旦开始不能中断。
包括以下三步:
执行生命周期方法 getSnapshotBeforeUpdate。 更新 DOM 树。执行生命周期方法 componentDidUpdate 或 useLayoutEffect。

总的来说:React Fiber 的引入,让 React 从一个“同步渲染引擎”转变为一个“异步可中断渲染引擎”。 增量化、可中断、可恢复

Webpack

核心概念:module、chunk 和 bundle,module 是任何通过 import 或者 require 导入的代码,包括 js、css、图片资源等;多个 module 可以组成一个 chunk,每个 chunk 经过处理后会输出一个 bundle 文件。

webpack解决了什么?

背景: 更高效地管理和维护项目中的每一个资源,通过文件划分的形式实现模块化,但是模块都是在全局中工作,大量模块成员污染了环境,模块与模块之间并没有依赖关系、维护困难、没有私有空间等问题。就出现了命名空间方式,规定每个模块只暴露一个全局对象,window.moduleA这种方式也并没有解决第一种方式的依赖等问题。再后来,我们使用立即执行函数为模块提供私有空间,通过参数的形式作为依赖声明。但是仍然存在一些没有解决的问题。我们是用过script标签在页面引入这些模块的,这些模块的加载并不受代码的控制,时间一久维护起来也十分的麻烦。

理想的解决方式是,在页面中引入一个JS入口文件,其余用到的模块可以通过代码控制,按需加载进来。除了模块加载的问题以外,还需要规定模块化的规范,如今流行的则是CommonJS、ES Modules。

需求:
1.监听文件的变化来并且反映到浏览器上,提高开发的效率
2.使用一些高级的特性来加快我们的开发效率或者安全性,比如通过ES6+、TypeScript开发脚本逻辑,通过sass、less等方式来编写css样式代码
3.开发完成后我们还需要将代码进行压缩、合并以及其他相关的优化

解决了解决模块依赖复杂的问题,资源整合与优化问题(代码压缩、文件分割),开发流程优化问题(热更新、自动化构建过程)、跨平台环境兼容性的问题(适配不同浏览器、支持多种环境)

webpack配置用过哪些?

一般在webpack.config.js的文件里面配置;

entry和output

  1. 单入口单出口,一般用于单页应用,最终只会产生一个 chunk。
  2. 多入口单出口。entry: ['./src/index1.js','./src/index2.js'], entry作为数组。
  3. 多入口多出口。 entry改为对象,key表示打包后输出文件的名字。
  4. output: filename:xxxx,path:reslove(__dirname,'build')

配置模式mode

默认production | development

JS语法检查

eslint-loader: 在eslintConfig配置项中设置 ,

  1. “rules”: { // eslint检查的规则 0 忽略 1 警告 2 错误
    “no-console”: 0, // 不检查console
    “eqeqeq”: 2, // 用而不用=就报错
    “no-alert”: 2 // 不能使用alert
    },
  2. “env”: { // 设置环境
    “browser”: true, // 支持浏览器环境: 能够使用window上的全局变量
    “node”: true // 支持服务器环境: 能够使用node上global的全局变量
    },

JS语法转换

babel-loader 将浏览器不能识别的新语法转换成原来识别的旧语法,做浏览器兼容性处理

js兼容性处理

  1. 使用经典的polyfill @babel/polyfill
    优点: 解决babel只能转换部分低级语法的问题(如:let/const/解构赋值…),引入polyfill可以转换高级语法(如:Promise…)
    2.core-js

打包样式文件中的图片资源

图片文件webpack不能解析,需要借助loader编译解。析添加2张图片:• 小图, 小于8kb • 大图, 大于8kb • 在less文件中通过背景图的方式引入图片
file-loader url-loader

  {test: /\.(png|jpg|gif)$/,use: {loader: 'url-loader',options: {limit: 8192, // 8kb --> 8kb以下的图片会base64处理outputPath: 'images', // 决定文件本地输出路径publicPath: '../build/images',  // 决定图片的url路径name: '[hash:8].[ext]' // 修改文件名称 [hash:8] hash值取8位  [ext] 文件扩展名}}},

打包HTML文件

html文件webpack不能解析,需要借助插件编译解析 html-webpack-plugin

打包html中图片资源

html中的图片url-loader没法处理,它只能处理js中引入的图片 / 样式中图片,不能处理html中img标签,需要引入其他html-loader处理。

webpack构建流程?

啊
初始化-编译构建-输出

1.初始化参数。获取我们在webpack.config.js文件配置的参数
2.然后开始编译,初始化一个叫compiler的对象,还有各种plugins插件,这个时候插件会开始监听webpack构建过程中的事件。
3.然后webpack要确定入口,一般是从entry开始,开始解析文件构建ast语法树,找抽依赖,递归下去。
4.这个递归的过程,根据文件类型和loader配置,调用相应的loader对不同的文件做转换处理,在找出该模块依赖的模块,递归本操作。
5.递归结束,编译后的 Module 组合成 Chunk,根据entry以及output等配置生成代码块chunk,输出到文件系统

Loader和Plugin的区别?

loader,它是一个转换器,将A文件进行编译成B文件,比如:将A.less转换为A.css,单纯的文件转换过程。

plugin是一个扩展器,它丰富了webpack本身,针对是loader结束后,它并不直接操作文件,而是基于事件机制工作,会监听webpack打包过程中的某些节点,执行广泛的任务。插件的范围包括,打包优化,代码压缩,甚至可以重新定义环境中的变量。

loader针对代码或资源,plugins针对工程。

官方文档说:相对于loader转换指定类型的模块功能,plugins能够被用于执行更广泛的任务比如打包优化、文件管理、环境注入等……

手写一个loader?

假设我们要写一个 loader,它的功能是将输入的文本内容里的所有单词首字母都转换为大写形式。

  1. 创建 loader 文件:uppercase-loader.js
module.exports = function (source) {const words = source.split(' ');const transformedWords = words.map(word => {return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();});return transformedWords.join(' ') + '\n';
};
  1. 使用 loader:要在 Webpack 项目中使用这个 loader,需要在 Webpack 配置文件(通常是 webpack.config.js)中进行配置
const path = require('path');module.exports = {entry: './src/index.js',output: {filename: 'main.js',path: path.resolve(__dirname, 'dist')},module: {rules: [{test: /\.txt$/, // 假设我们要处理的是.txt文件内容use: [path.resolve(__dirname, 'uppercase-loader.js') // 使用我们自定义的loader]}]}
};

通过 module.rules 数组来定义模块的处理规则。test 属性指定了要应用该规则的文件类型,use 配置中指定了要使用的 loader这样,当 Webpack 打包项目时,如果遇到 .txt 文件,就会使用我们自定义的 uppercase-loader 来处理文件内容,将其中的单词首字母都转换为大写形式。

JS

null和undefined区别

1.含义上来说null表示空对象,undefined是未定义
2.undefined在js中不是一个保留字,null是
3.

 let null = 1; // 语法错误
function undefined() {} // 语法错误
console.log(typeof null); // "object"  历史问题  对象类型的类型标记位为 000,而 null 在底层表示上全是 0,
console.log(typeof undefined); // "undefined"
console.log(null == undefined); // true
console.log(null === undefined); // false
```。
4.使用场景: 
nudefined 变量声明但未赋值时,访问对象不存在的属性时,函数没有显式返回值时。  null将某个对象赋值为空,以便垃圾回收器进行回收。##  JS编写的规范- 代码中出现地址、时间等字符串时需要使用常量代替。- 在进行比较的时候吧,尽量使用'===', '!=='代替'==', '!='- 不要在内置对象的原型上添加方法,如 Array, Date。- switch 语句必须带有 default 分支。- for 循环必须使用大括号。- if 语句必须使用大括号。## 原型链
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/542fb1076ae24268bd35c8ea2c3530c0.png)
原型对象:每个函数在创建的时候,都会生成一个属性prototype,这个prototype指向一个对象,这个对象就是函数的原型对象。比如说 function Person() {}  Person.prototype = person.__proto;  你把这个person new成实例对象之后,每个实例对象都有一个 __proto__ 属性(又叫隐式原型属性),指向它构造函数的原型对象。原型链又叫隐式原型链,原型链的作用是用来查找对象的属性的,如果一个属性A.name在当前的对象上没有找到就会沿着原型链向上查找,直到找到这个属性或者到达**原型链的顶端。Object.prototype  ===null**Object的hasOwnProperty()方法返回一个布尔值,判断对象是否包含特定的自身(非继承)属性。

http://www.mrgr.cn/news/80017.html

相关文章:

  • 基于Qwen2-VL模型针对LaTeX OCR任务进行微调训练 - 训练过程
  • Qt编写RK3588视频播放器/支持RKMPP硬解/支持各种视音频文件和视频流/海康大华视频监控
  • k8s service 配置AWS nlb load_balancing.cross_zone.enabled
  • 牛客月赛106(0/1最短路,树存最长链)
  • 磁盘阵列服务器和普通服务器的区别
  • c++作业4
  • ansible自动化运维(三)jinja2模板roles角色管理
  • uni-app实现小程序、H5图片轮播预览、双指缩放、双击放大、单击还原、滑动切换功能
  • 【数据结构进阶】AVL树深度剖析 + 实现(附源码)
  • 【电机控制器】FM33LF015芯片——FLASH模拟EEPROM
  • 黑皮书-计算机科学导论02
  • react-dnd 拖拽事件与输入框的文本选中冲突
  • Opencv之图像添加水印
  • HCIA-Access V2.5_2_2网络通信基础_TCP/IP协议栈报文封装
  • SAP FICO物料分类账
  • 任务4 DNS服务配置与管理
  • ubuntu22.04 使用crash
  • SpringBoot 手动实现动态切换数据源 DynamicSource (中)
  • 【大前端vue:组件】鼠标上移 出现动画
  • pyfink1.20版本下实现消费kafka中数据并实时计算
  • 【架构】从 Socket 的角度认识非阻塞模型
  • xshell连接虚拟机,更换网络模式:NAT->桥接模式
  • 网络基础 - TCP/IP 五层模型
  • 爬虫基础知识点
  • 设计模式——Singleton(单例)设计模式
  • 12.12 深度学习-注意力机制