做玻璃瓶的网站,网站生成静态,网站建设的方案实施包括,新品怎么推广效果最好React
fiber架构
1.为什么会出现 React fiber 架构?
React 15 Stack Reconciler 是通过递归更新子组件 。由于递归执行#xff0c;所以更新一旦开始#xff0c;中途就无法中断。当层级很深时#xff0c;递归更新时间超过了 16ms#xff0c;用户交互就会卡顿。对于特别庞…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工作流程
调度阶段Scheduling 当组件的状态或属性发生变化时React 会通过setState等方式触发更新。把待更新的任务会先放入队列中, 然后通过 requestIdleCallback 请求浏览器调度。 协调阶段Reconciliation 现在浏览器有空闲或者超时了就会构建 Fiber 树workInProgress Fiber树对比 Fiber 树通过一种称为 “双缓存” 的技术将新的workInProgress Fiber树与旧的 Fiber 树进行对比找出需要更新的节点这个过程称为 “Diffing”。 渲染阶段Render 根据协调阶段对比的结果生成 DOM 更新操作移动更新删除这些操作会被记录在一个称为effect list的链表中批量提交到浏览器的 DOM 中。 提交阶段Commit React 会遍历effect list按照顺序执行其中的 DOM 更新操作React 会根据操作的类型调用相应的 DOM API如createElement、setAttribute、appendChild等。 渲染完成后React 会根据组件的类型和状态调用相应的生命周期函数或回调函数。
总的来说React Fiber 的引入让 React 从一个“同步渲染引擎”转变为一个“异步可中断渲染引擎”。 增量化、可中断、可恢复
React渲染流程
jsx ---- render function ---- vdom ----- Fiber ------ DOM 在编译阶段Babel 等工具会将 JSX 代码转换为 React.createElement 函数调用的形式。React.createElement 返回的 React 元素是一个普通的 JavaScript 对象,这些对象构成了虚拟 DOM 树。每个虚拟 DOM 节点遍历创建对应的 Fiber 树。Fiber 树是一种链表结构每个 Fiber 节点都有指向父、子节点和兄弟节点的指针方便进行遍历和更新操作。在构建完 Fiber 树后React 会根据 Fiber 树中的信息创建实际的 DOM 节点。
对React的理解
react是一个用于构建用户界面的JS库。 怎么构建界面的呢fnreactui。
官网强调 “组件是 React 的基石”。通过组件化将用户界面拆分成一个个独立的、可复用的组件。一个按钮、一个表单、一个导航栏等都可以是一个组件每个组件都有自己的状态和生命周期通过组合不同的组件来构建复杂的应用界面很好维护。其次在构建界面的时候在代码的写法采用声明式编程 风格只需要描述界面应该呈现的样子而不需要直接操作 DOM 来进行界面更新。当数据发生变化时React 会自动根据新的数据重新渲染组件。那在这个组件渲染状态变化的过程React 引入了虚拟 DOM的概念 React 会先在虚拟 DOM 上进行更新操作然后通过对比新旧虚拟 DOM 的差异只将实际需要更新的部分高效地应用到真实 DOM 上从而提高渲染性能。
不建议在if语句内使用 Hook
在 React 内部Hook 是通过链表的数据结构来存储和管理的。当组件首次挂载时React 会按照 Hook 的调用顺序依次将它们添加到链表中并为每个 Hook 分配一个唯一的索引。在if语句内使用 Hook可能会破坏 Hook 的调用顺序 Hook 链表的结构和索引就会与首次渲染时不同。 循环语句 || 函数嵌套 || 异步函数 || 条件渲染组件
声明式编程和命令式编程
声明式编程更注重描述要做什么而不是具体怎么做。 命令式编程则侧重于描述具体的操作步骤和执行顺序即告诉计算机如何一步一步地完成任务。
// 声明式写法
const DeclarationExample () {return (divh1Hello, World!/h1pThis is a declarative example in React./p/div);
};
在上面的例子中用 JSX 描述了一个简单的 React 组件它声明了 UI 的结构和内容。React 负责将这个声明传递给虚拟 DOM 并进行渲染我们不需要直接操作底层的 DOM。
// 命令式写法
const ImperativeExample () {const container document.createElement(div);const heading document.createElement(h1);heading.textContent Hello, World!;const paragraph document.createElement(p);paragraph.textContent This is an imperative example in plain JavaScript.;container.appendChild(heading);container.appendChild(paragraph);// 将容器添加到页面中document.body.appendChild(container);
};
使用原生 JavaScript 创建了 DOM 元素并通过命令式的方式逐步操作这些元素的创建和组装过程。这样的写法更注重详细的步骤和控制。 总体而言声明式的代码更直观和简洁而命令式的代码更灵活可以更精细地控制每个步骤。
react中state和constructor的区别
state 在组件内部存储和管理数据专门用于存储组件的可变数据这些数据通常与组件的用户交互、业务逻辑等相关。例如一个输入框组件的输入值、一个列表组件的列表数据等都可以存储在state中。可以根据需要多次调用。 **constructor**本身并不直接存储数据而是用于初始化组件所需的数据和操作。如绑定this指针等但它不会直接存储组件的业务数据。在组件实例化时只被调用一次用于进行组件的初始化操作。之后无论组件的状态如何变化constructor都不会再次被调用除非重新创建组件实例。
函数组件和类组件的区别
定义方式 类组件 使用 ES6 的class定义需要继承React.Component或React.PureComponent并且必须用render方法来返回组件的 UI 结构。 函数组件 是一个Js函数接收props作为参数返回一个 React 元素来描述组件的 UI 结构。状态管理 类组件 通过this.state来存储和管理组件的内部状态。具有丰富的生命周期方法。 函数组件 在hooks出来之前函数组件是无状态的被称为 “纯函数组件”。在没有 Hooks 之前函数组件不存在生命周期的概念。引入 Hooks 后可以使用useEffect等钩子函数来模拟类组件的部分生命周期行为。使用场景 类组件 在处理复杂表单时类组件的状态管理和生命周期方法能更好地处理input表单数据的收集、验证和提交。 包括我的组件库搭建时候弹窗组件动画与过渡效果需要在组件挂载、更新或卸载时添加动画或过渡效果类组件的生命周期方法提供了更精细的控制。 函数组件 实时数据展示与交互如实时聊天应用中的消息列表组件使用函数组件结合useEffect和useState可以方便地监听消息数据的变化并实时更新界面。
受控组件和非受控组件 以及类组件和函数组件的关系
在 React 中受控组件和非受控组件是从组件数据处理方式 角度进行的分类而类组件和函数组件则是从组件的定义形式 角度进行的划分。 受控组件 其值受到 React 状态的控制通常通过onChange等事件来更新状态并且表单元素的值由状态来决定。 非受控组件 其值不受 React 状态控制而是由 DOM 本身来管理。通常通过ref来获取 DOM 元素的值在需要时进行操作。例如一个只有一个输入框的登录表单使用非受控组件可以快速完成功能开发。
React事件机制
事件处理流程
事件触发当用户在浏览器中执行某个操作如点击按钮、输入文本等浏览器会触发相应的原生事件。事件委托React 采用了事件委托的机制将所有的事件都绑定在组件的根元素上。当事件发生时通过事件冒泡机制事件会从触发的目标元素向上冒泡到组件的根元素。合成事件生成在事件冒泡到根元素的过程中React 会根据原生事件创建相应的合成事件对象并将其传递给事件处理函数。事件处理函数执行React 会调用绑定在元素上的事件处理函数并将合成事件对象作为参数传递给它。在事件处理函数中开发者可以根据需要进行相应的操作如更新状态、调用其他函数等。
react所有事件都挂在documnet对象上先触发真实dom事件再触发react事件最后执行document上挂载的事件。 Webpack
核心概念module、chunk 和 bundlemodule 是任何通过 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
单入口单出口一般用于单页应用最终只会产生一个 chunk。多入口单出口。entry: [./src/index1.js,./src/index2.js], entry作为数组。多入口多出口。 entry改为对象key表示打包后输出文件的名字。output filenamexxxxpathreslove(__dirname,build)
配置模式mode
默认production | development
JS语法检查
eslint-loader: 在eslintConfig配置项中设置
“rules”: { // eslint检查的规则 0 忽略 1 警告 2 错误 “no-console”: 0, // 不检查console “eqeqeq”: 2, // 用而不用就报错 “no-alert”: 2 // 不能使用alert },“env”: { // 设置环境 “browser”: true, // 支持浏览器环境 能够使用window上的全局变量 “node”: true // 支持服务器环境: 能够使用node上global的全局变量 },
JS语法转换
babel-loader 将浏览器不能识别的新语法转换成原来识别的旧语法做浏览器兼容性处理
js兼容性处理
使用经典的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它的功能是将输入的文本内容里的所有单词首字母都转换为大写形式。
创建 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;
};使用 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是
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 语句必须使用大括号。
原型链 原型对象每个函数在创建的时候都会生成一个属性prototype这个prototype指向一个对象这个对象就是函数的原型对象。比如说 function Person() {} Person.prototype person.__proto; 你把这个person new成实例对象之后每个实例对象都有一个 proto 属性(又叫隐式原型属性)指向它构造函数的原型对象。原型链又叫隐式原型链原型链的作用是用来查找对象的属性的如果一个属性A.name在当前的对象上没有找到就会沿着原型链向上查找直到找到这个属性或者到达原型链的顶端。Object.prototype.__proto__的值是null Object的hasOwnProperty()方法返回一个布尔值判断对象是否包含特定的自身非继承属性。 Object.prototype.__proto__设置为null就表示原型链在这里结束了再往上就没有其他对象可查找了这符合原型链的设计逻辑。如果Object.prototype的__proto__指向了其他非null对象那么在进行原型链查找时就会继续沿着这个指向去查找可能会导致无限循环或者不必要的查找开销。