【React学习】React更新渲染原理

2023-11-13

当我们调用 setState 之后发生了什么?react经历了怎样的过程将新的 state 渲染到页面上?

一次react更新,核心就是对虚拟dom进行diff,找出最少的需要变化的dom节点,然后对其进行相应的dom操作,用户即可在页面上看到更新。但 react 作为广泛使用的框架,需要考虑更多的因素,考虑多个更新的优先级,考虑主线程占用时长,考虑diff算法复杂度,考虑性能。。等等,本文就来探讨一下react在其内部是如何处理数据更新的。

react在内部使用fiber这种数据结构来作为虚拟dom【react16+】,它与dom tree一一对应,形成fiber tree,一次react更新,本质是fiber tree结构的更新变化。而fiber tree结构的更新,用更专业的术语来讲,其实就是fiber tree的协调(Reconcile)。Reconcile中文意思是调和、使一致,协调fiber tree,就是调整fiber tree的结构,使其和更新后的jsx模版结构、dom tree保持一致。

react从16起,将更新机制分为三个模块,也可以说是三个步骤,分别是Schedule【调度】、Reconcile【协调】、render【渲染】

Schedule

为什么需要Schedule?

首先我们要知道react在进行协调时,提供了两种模式:Legacy mode 同步阻塞模式和 Concurrent mode 并行模式。

不同上下文中的更新会触发不同的模式,如果是在 eventsetTimeoutnetwork requestcallback 中触发更新,react 会采用 Legacy 模式。如果更新与 SuspenseuseTransitionOffScreen 相关,那么 react 会采用 Concurrent 模式。

Legacy mode

Legacy mode在协调时会启动 workLoopSyncworkLoopSync 开始工作以后,要等到所有 fiber node 都处理完毕以后,才会结束工作,也就是 fiber tree 的协调过程不可中断。

Legacy mode存在的问题:如果 fiber tree 的结构很复杂,那么协调 fiber tree 可能会占用大量的时间,导致主线程会一直被 js 引擎占用,渲染引擎无法在规定时间(浏览器刷新频率 - 16.7ms)内完成工作,使得页面出现卡顿(掉帧),影响用户体验。

Concurrent mode

鉴于Legacy mode存在的问题,react团队在react 16中提出了 Concurrent mode的概念,并在react 18中开放使用。react16、17一直为此做准备。

Concurrent 模式最大的意义在于,使用Concurrent 模式以后的react的应用可以做到:

  • 协调可以中断、恢复;不会长时间阻塞浏览器渲染
  • 高优先级更新可以中断低优先级更新,优先渲染

那么,怎么做到这两点呢?

事实上,Schedule就是用来完成这个任务的,调度任务的优先级,使高优先级任务优先进入Reconcile,并且提供中断和恢复机制。

时间切片

react采用时间切片的方式来实现协调的中断和恢复,Concurrent mode在协调时会启动 workLoopConcurrentworkLoopConcurrent 开始工作以后,每次协调 fiber node 时,都会判断当前时间片是否到期。如果时间片到期,会停止当前 workLoopConcurrent,让出主线程,然后请求下一个时间片继续协调。

协调的中断及恢复,类似于浏览器的eventloop,js引擎和渲染引擎互斥,在主线程中交替工作。

我们可以通过模拟 eventLoop来实现时间分片以及重新请求时间片。一段 js 程序,如果在规定时间内没有结束,那我们可以主动结束它,然后请求一个新的时间片,在下一个时间片内继续处理上一次没有结束的任务。

let taskQueue = [];   // 任务列表
let shouldTimeEnd = 5ms;   // 一个时间片定义为 5ms
let channel = new MessageChannel();  // 创建一个 MessageChannel 实例
​
function wookLoop() {
    let beginTime = performance.now();  // 记录开始时间
    while(true) { // 循环处理 taskQueue 中的任务
        let currentTime = performance.now();  // 记录下一个任务开始时的时间
        if (currentTime - beginTime >= shouldTimeEnd) break;  // 时间片已经到期,结束任务处理
        processTask();  // 时间片没有到期,继续处理任务
  }
    if (taskQueue.length) { // 时间片到期,通过调用 postMessage,请求下一个时间片
        channel.port2.postMessage(null); 
  }
}
​
channel.port1.onmessage = wookLoop;  // 在下一个时间片内继续处理任务
workLoop(); 

和浏览器的消息队列 一样, react 也会维护一个任务队列 taskQueue,然后通过 workLoop 遍历 taskQueue,依次处理 taskQueue 中的任务。

taskQueue 中收集任务是有先后处理顺序的,workLoop 每次处理 taskQueue 中的任务时,都会挑选优先级最高的任务进行处理。

每触发一次 react 更新,意味着一次 fiber tree 的协调,但协调并不会在更新触发时立刻同步进行。相反,react 会为这一次更新,生成一个 task,并添加到 taskQueue 中,fiber tree 的协调方法会作为新建 taskcallback。当 wookLoop 开始处理该 task 时,才会触发 taskcallback,开始 fiber tree 的协调。

任务的优先级

react在内部定义了 5 种类型的优先级,以及对应的超时时间timeout

  • ImmediatePriority, 直接优先级,对应用户的 clickinputfocus 等操作; timeout为 -1,表示任务要尽快处理;
  • UserBlockingPriority,用户阻塞优先级,对应用户的 mousemovescroll 等操作;timeout 为 250 ms;
  • NormalPriority,普通优先级,对应网络请求、useTransition 等操作; timeout 为 5000 ms;
  • LowPriority,低优先级(未找到应用场景);timeout 为 10000 ms;
  • IdlePriority,空闲优先级,如 OffScreen; timeout 为 1073741823 ms;

5 种优先级的顺序为: ImmediatePriority > UserBlockingPriority > NormalPriority > LowPriority > IdlePriority

在确定了任务的优先级以后,react 会根据优先级为任务计算一个过期时间 expirationTime,即 expirationTime = currentTime + timeout,然后根据 expirationTime 时间来决定任务处理的先后顺序。

expirationTime越小的任务会被排在task队列的越前面,之所以需要timeout,而不是直接对比优先级等级,是为了避免低优先级任务长时间被插队而导致一直无响应;同时,在时间分片到期时,需要根据expirationTime判断下一个要处理的任务是否过期,如果已过期,就不能让出主线程,需要立即处理。

⚠️注:react17中用Lanes重构了优先级算法,此处不展开陈述,有兴趣的同学可查阅相关文档。

获取最先处理的task

react 采用了小顶堆来存储task,实现最小优先队列,即 taskQueue 是一个小顶堆,放在堆顶的task是需要最先处理的。

使用最小堆时,有三个操作:pushpoppeek

  • push,入堆操作,即将 task 添加到 taskQueue 中。添加一个新创建的 task 时,会将 task 添加到最小堆的堆底,然后对最小堆做自底向上的调整。调整时,会比较堆节点(task) 的 expirationTime,将 expirationTime 较小的 task 向上调整。* peek,获取堆顶元素,即获取需要最先处理的 task,执行 taskcallback,开始 fiber tree 的协调。* pop,堆顶元素出堆,即 task 处理完毕,从 taskQueue 中移除。移除堆顶元素以后,会对最小堆做自顶向下的调整。调整时,也是比较堆节点(task) 的 expirationTime,将 expirationTime 较大的 task 向下调整。### 高优先级的更新中断低优先级的更新

Concurrent 模式下,如果在低优先级更新的协调过程中,有高优先级更新进来,那么高优先级更新会中断低优先级更新的协调过程。

每次拿到新的时间片以后,workLoopConcurrent 都会判断本次协调对应的优先级和上一次时间片到期中断的协调的优先级是否一样。如果一样,说明没有更高优先级的更新产生,可以继续上次未完成的协调;如果不一样,说明有更高优先级的更新进来,此时要清空之前已开始的协调过程,从根节点开始重新协调。等高优先级更新处理完成以后,再次从根节点开始处理低优先级更新。

Reconcile

前面说到,reconcile(协调)就是fiber tree 结构的更新,那么具体是怎样更新的呢?本小节就来解答这个问题。

前置知识

从jsx到dom

Step1: 从jsx生成react element

jsx 模板通过 babel 编译为 createElement 方法;执行组件方法,触发 createElement 的执行,返回 react element

Step2: 从react element生成fiber tree

  • fiber tree 中存在三种类型的指针 childsiblingreturn。其中,child 指向第一个子节点,sibling 指向兄弟节点,return 指针指向父节点;* fiber tree 采用的深度优先遍历,如果节点有子节点,先遍历子节点;子节点遍历结束以后,再遍历兄弟节点;没有子节点、兄弟节点,就返回父节点,遍历父节点的兄弟节点;* 当节点的 return 指针返回 null 时,fiber tree 的遍历结束;Step3: fiber tree生成之后,从fiber tree到真实dom,就是处理fiber tree上对应的副作用,包括:

  • 所有 dom 节点的新增;

  • componentDidMountuseEffectcallback 函数的触发;

  • ref 引用的初始化;

双缓存fiber tree

react 做更新处理时,会同时存在两颗 fiber tree。一颗是已经存在的 old fiber tree,对应当前屏幕显示的内容,称为 current fiber tree;另外一颗是更新过程中构建的 new fiber tree,称为 workInProgress fiber tree

current fiber treeworkInProgress fiber tree可以通过alternate指针互相访问

当更新完成以后,使用 workInProgress fiber tree 替换掉 current fiber tree,作为下一次更新的 current fiber tree

协调的过程

协调过程中主要做三件事情:

1.为 workInProgress fiber tree 生成 fiber node

2.为发生变化的 fiber node标记副作用 effect

3.收集带 effectfiber node

生成workInProgress fiber tree

workInProgress fiber tree 作为一颗新树,生成 fiber node 的方式有三种:

  • 克隆(浅拷贝) current fiber node,意味着原来的 dom 节点可以复用,只需要更新 dom 节点的属性,或者移动 dom 节点;
  • 新建一个 fiber node,意味着需要新增加一个 dom 节点;
  • 直接复用 current fiber node,表示对应的 dom 节点完全不用做任何处理;

复用的场景:当子组件的渲染方法(类组件的 render、函数组件方法)没有触发,(比如使用了React.memo),没有返回新的 react element,子节点就可以直接复用 current fiber node

在日常开发过程中,我们可以通过合理使用 ShouldComponentUpdateReact.memo,阻止不必要的组件重新 render,通过直接复用 current fiber node,加快 workInProgress fiber tree 的协调,达到优化的目的。

相反,只要组件的渲染方法被触发,返回新的 react element,那么就需要根据新的 react element 为子节点创建 fiber node(通过浅拷贝或新建)。

  • 如果能在 current fiber tree 中找到匹配节点,那么可以通过克隆(浅拷贝) current fiber node 的方式来创建新的节点;

  • 相反,如果无法在 current fiber tree 找到匹配节点,那么就需要重新创建一个新的节点;

我们常说的diff算法就是发生在这一环节。

diff算法比较的双方是 workInProgress fiber tree 中用于构建 fiber nodereact elementcurrent fiber tree 中的 fiber node,比较两者的 keytype,根据比较结果来决定如何为 workInProgress fiber tree 创建 fiber node

【 key 和 type 】:

key就是 jsx 模板中元素上的 key 属性。如果不写默认为undefinedjsx 模板转化为 react element 后,元素的 key 属性会作为 react elementkey 属性。同样的,react element 转化为 fiber node 以后,react elementkey 属性也会作为 fiber nodekey 属性。

jsx 中不同的元素类型,有不同的type

<Component name="xxxx" />  //type = Component, 是一个函数
<div></div>    // type = "div", 是一个字符串
<React.Fragment></React.Fragment>  // type = React.Fragment, 是一个数字(react 内部定义的); 

jsx 模板转化为 react element 以后,react elementtype 属性会根据 jsx 元素的类型赋不同的值,可能是组件函数,也可能是 dom 标签字符串,还可能是数字。 react element 转化为 fiber node 以后,react elementtype 属性也会作为 fiber nodetype 属性。

综上,判断拷贝 current fiber node 的逻辑,概括来就是:

reactElement.key === currentFiberNode.key && reactElement.type === currentFiberNode.type, current fiber node //可以克隆;

reactElement.key !== currentFiberNode.key, current fiber node //不可克隆;

reactElement.key === currentFiberNode.key && reactElement.type !== currentFiberNode.type, current fiber node //不可克隆; 

diff 算法:

  • 已匹配的父节点的直接子节点进行比较,不跨父节点比较;
  • 通过比较 keytype 来判断是否需要克隆 current fiber node。只有 keytype 都相等,才克隆 current fiber node 作为新的节点,否则就需要新建一个节点。key 值和节点类型typekey 的优先级更高。如果 key 值不相同,那么节点不可克隆。
  • 当比较 single react elementcurrent fiber node list 时,只需要遍历 current fiber node list,比较每个 current fiber nodereact elementkey 值和 type。只有 keytype 都相等,react elementcurrent fiber node 才能匹配。如果有匹配的,直接克隆current fiber node,作为 react element 对应的 workInProgress fiber node。如果没有匹配的 current fiber node,就需要为 react element 重新创建一个新的 fiber node 作为 workInProgress fiber node
  • 当比较react element listcurrent fiber node list 时,还需要通过列表下标 index 判断 wokrInProgress fiber node 是否相对于克隆的 current fiber node 发生了移动。这也是diff中最复杂的地方。

为发生变化的fiber node标记effect

判断节点是否发生变化:

  • 节点只要是重新创建的而不是克隆自 current fiber node,那么节点就百分之百发生了变化,需要更新;* 节点克隆自 current fiber node,需要比较 props 是否发生了变化,如果 props 发生了变化,节点需要更新;* 节点克隆自 current fiber node,且是组件类型,还需要比较 state 是否发生了变化,如果 state 发生了变化,节点需要更新;常见的effect类型:

  • Placement,放置,只针对 dom 类型的 fiber node,表示节点需要做移动或者添加操作。

  • Update,更新,针对所有类型的 fiber node,表示 fiber node 需要做更新操作。

  • PlacementAndUpdate,放置并更新,只针对 dom 类型的 fiber node,表示节点发生了移动且 props 发生了变化。

  • Ref,表示节点存在 ref,需要初始化 / 更新 ref.current

  • Deletion,删除,针对所有类型的 fiber node,表示 fiber node 需要移除。

  • Snapshot,快照,主要是针对类组件 fiber node。当类组件 fiber node 发生了 mount 或者 update 操作,且定义了 getSnapshotBeforeUpdate 方法,就会标记 Snapshot

  • Passive,主要针对函数组件 fiber node,表示函数组件使用了 useEffect。当函数组件节点发生 mount 或者 update 操作,且使用了 useEffect hook,就会给 fiber node 标记 Passive

  • Layout,主要针对函数组件 fiber node,表示函数组件使用了 useLayoutEffect。当函数组件节点发生 mount 或者 update 操作,且使用了 useLayoutEffect hook,就会给 fiber node 标记 Layout

react 使用二进制数来声明 effect,如 Placement 为 2 (0000 0010),Update 为 4 (0000 0100)。一个 fiber node 可同时标记多个 effect,如函数组件 props 发生变化且使用了 useEffect hook,那么就可以使用 Placement | Update = 516(位运算符) 来标记。

收集带 effectfiber node

如果一个 fiber node 被标记了 effect,那么 react 就会在这个 fiber node 完成协调以后,将这个 fiber node 收集到effectList中。当整颗 fiber tree 完成协调以后,所有被标记 effectfiber node 都被收集到一起。

收集fiber nodeeffectList 采用单链表结构存储,firstEffect 指向第一个标记 effectfiber nodelastEffect 标记最后一个 fiber node,节点之间通过 nextEffect 指针连接。

由于 fiber tree 协调时采用的顺序是深度优先,协调完成的顺序是子节点、子节点兄弟节点、父节点,所以收集带 effect 标记的 fiber node 时,顺序也是子节点、子节点兄弟节点、父节点。

Render

render也称为commit,是对协调过程中标记的effect 的处理

effect 的处理分为三个阶段,这三个阶段按照从前到后的顺序为:

1.before mutation 阶段 (dom 操作之前)

2.mutation 阶段 (dom 操作)

3.layout 阶段 (dom 操作之后)

不同的阶段,处理的 effect 种类也不相同。在每个阶段,react 都会从 effectList 链表的头部 - firstEffect 开始,按序遍历 fiber node, 直到 lastEffect

before mutation 阶段

before mutation 阶段的主要工作是处理带 Snapshot 标记的 fiber node。 从 firstEffect 开始遍历 effect 列表,如果 fiber nodeSnapshot 标记,触发 getSnapshotBeforeUpdate 方法。

mutation 阶段

mutation 阶段的主要工作是处理带 DeletionPlacementPlacementAndUpdateUpdate 标记的 fiber node。 在这一阶段,涉及到 dom 节点的更新、新增、移动、删除,组件节点删除导致的 componentWillUnmountdestory 方法的触发,以及删除节点引发的 ref 引用的重置。

dom 节点的更新:

  • 通过原生的 API setAttributeremoveArrribute 修改 dom 节点的 attr
  • 直接修改 dom 节点的 style
  • 直接修改 dom 节点的 innerHtmltextContent

dom 节点的新增和移动:

  • 如果新增(移动)的节点是父节点的最后一个子节点,那么可以直接使用 appendChild 方法。

  • 如果不是最后一个节点,需要使用 insertBefore 方法。通过遍历找到第一个没有带Placement标记的节点作为insertBefore的定位元素。

dom节点的删除:

  • 如果节点是 dom 节点,通过 removeChild 移除;
  • 如果节点是组件节点,触发 componentWillUnmountuseEffectdestory 方法的执行;
  • 如果标记 Deletion 的节点的子节点中有组件节点,深度优先遍历子节点,依次触发子节点的 componentWillUnmountuseEffectdestory 方法的执行;
  • 如果标记 Deletion 的节点及子节点关联了 ref 引用,要将 ref 引用置空,及 ref.current = null(也是深度优先遍历);

layout 阶段

layout 阶段的主要工作是处理带 update 标记的组件节点和带 ref 标记的所有节点。 工作内容如下:

  • 如果类组件节点是mount操作,触发 componentDidMount;如果是 update 操作,触发 componentDidUpdate
  • 如果函数组件节点时 mount 操作,触发 useLayoutEffectcallback;如果是 update 操作,先触发上一次更新生成的 destory,再触发这一次的 callback
  • 异步调度函数组件的 useEffect
  • 如果组件节点关联了 ref 引用,要初始化 ref.current;

最后

整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。

有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享

部分文档展示:



文章篇幅有限,后面的内容就不一一展示了

有需要的小伙伴,可以点下方卡片免费领取

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【React学习】React更新渲染原理 的相关文章

  • 浏览器视口大小(以设备像素为单位)

    Goal 我希望 Flash 能够获得有关浏览器视口宽度和高度 以设备像素为单位 的准确信息初始化 调整大小或浏览器缩放事件时 规格 我需要将 flash 嵌入到在 chrome safari firefox 等中运行的 html 页面中
  • 从函数返回函数的目的是什么?

    阅读一些遗留代码 发现 A prototype setSize function var v1 new Vector2 return function size var halfSize v1 copy size multiplyScala
  • 如何在没有 jQuery 的情况下删除 Javascript 中的元素

    我试图通过以下方式从 DOM 中删除 Div a 标签嵌套在其中 我想我正在寻找的是 jQuery 的纯 Javascript 版本 div remove 这是html设置 div a href Click me to remove the
  • 按下回车键时不刷新页面

    我遇到了一些问题 只要表单中有输入 回车键就会触发页面刷新 下面的代码 如果按下回车并且文本区域 input 中没有输入任何文本 则不会刷新页面 但是如果按下回车并且 input中有输入或者光标位于文本区域 我不确定是什么触发了它 因为 s
  • ReactTransitionGroup 不适用于 React-redux 连接组件

    我正在开发一个更大的项目 但我创建了这个简短的示例来说明问题 如果我使用Box组件 它的工作原理 它在控制台中输出componentWillEnter and componentWillLeave当我们点击按钮时 如果我使用BoxConta
  • 如何使用角度材料在具有可扩展行的表格中创建嵌套垫表

    我有以下数据 id c9d5ab1a subdomain wing domain aircraft part id c9d5ab1a info mimetype application json info dependent parent
  • IE 中的 XPath 查询使用从零开始的索引,但 W3C 规范是从一开始的。我应该如何处理差异?

    问题 我正在转换目前仅适用于 Internet Explorer 的相对较大的 Javascript 代码 以便使其也适用于其他浏览器 由于代码广泛使用 XPath 我们做了一些兼容性功能以使事情变得更容易 function selectN
  • 如何使用 Javascript 设置查询字符串

    有没有办法使用 javascript 设置查询字符串的值 我的页面有一个过滤器列表 单击该列表时 它将更改右侧的页内结果窗格 我正在尝试更新 url 的查询字符串值 因此如果用户离开页面 然后单击 后退 按钮 他们将返回到最后一个过滤器选择
  • onclick 事件中未调用函数

    我想在每个 YouTube 链接的末尾添加一些 HTML 以在 litebox 中打开播放器 到目前为止 这是我的代码 document ready function var valid url new RegExp youtube com
  • 表单发布请求并存储收到的数据

    我有一个非常简单的表单 在提交时发出发布请求
  • 使用 Javascript 设置 cookie [重复]

    这个问题在这里已经有答案了 我正在尝试构建我的第一个移动应用程序 它需要连接到我的 mysql 数据库并使用 json 返回数据 这很好 目前我有一个登录系统 一旦确定用户名和密码存在 它就会返回一条成功消息 对于下一步 我想在我的页面上使
  • 如何使用 JavaScript 或 jQuery 克隆 HTML 元素的样式对象?

    我正在尝试克隆元素的样式对象 这应该允许我在更改后重置所述元素的样式 例如 el style left 50px curr style left 50px Modify the elements style The cloned style
  • Rails 3.1+ 的 Jasmine 与 Mocha JavaScript 测试 [已关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我对茉莉花有经验并且非常喜欢它 有谁有 Jasmine 和 Mocha 的经验 特别是 Rails 的经验吗 我想知道是否值得转用 我已经在 J
  • 主页(网格)上的缩略图现在显得模糊。如何纠正?

    我不知道这看起来是否愚蠢 但从早上开始我就无法纠正这个突然出现在我的博客网站上的错误www candidopinions in http www candidopinions in 我有一个网格视图模板 其中博客文章中的特色图像作为调整大小
  • 使用 Enzyme 测试 `React.createRef` api

    我想测试下面的类 它使用React createRef api 不过 快速搜索并没有发现任何这样做的例子 有人成功过吗 我该如何嘲笑裁判 理想情况下我想使用shallow class Main extends React Component
  • 滚动顶部不符合预期

    Note 由于上次忘记奖励而重新开放赏金 A Woff 大师已经给出答案 我想在用户展开某一行时到达该行 这样当最后一个可见行展开时 用户不必向下滚动即可查看内容 I used example tbody on click td green
  • Flot 库将 y 轴设置为最小值 0 和最大值 24

    如何将 y 轴设置在 0 到 24 的范围内 这是我的代码 j plot j placeholder d1 xaxis mode time min new Date 2010 11 01 getTime max new Date 2011
  • 如何从 json 文件创建模型? (ExtJS)

    这是我想使用 json 文件创建的模型 Ext define Users extend Ext data Model fields name user id type int name user name type string 为了根据服
  • 仅当显式选择行时才关闭 ui-bootstrap typeahead

    我创建了这个jsBin http jsbin com livuqafe 2 edit来证明我遇到的问题 如果您转到此处 请尝试输入 五 并继续 你的自然反应是输入 五 然后按 Tab 如果你想要 五百 你可以向下箭头一次 但是 在这种情况下
  • 没有输入的 jQuery 日期选择器

    我有一个相当复杂的网络应用程序 我想向其中添加一些日期选择 UI 我遇到的问题是我无法从文档中弄清楚如何真正控制日期选择器的出现方式和时间 不涉及任何表单元素 不 我不会添加秘密表单字段 因此简单的开箱即用方法根本行不通 我希望有人可以提供

随机推荐

  • 陀螺产业区块链第二季

    2020年4月 国家发改委在例行新闻发布会上宣布区块链被正式列为新型基础设施中的信息基础设施 自此区块链正式搭上新基建的 风口 与传统基础设施建设相比 新型基础设施建设更加侧重于突出产业转型升级的新方向 无论是 5G还是区块链 都体现出加快
  • 常见的二十种软件测试方法详解(史上最全)

    一 单元测试 模块测试 单元测试是对软件组成单元进行测试 其目的是检验软件组成单位的正确性 测试对象是 模块 对模块进行测试 单独的一个模块测试 属于静态测试的一类 测试阶段 编码后或者编码前 TDD 测试对象 最小模块 测试人员 白盒测试
  • 深入浅出mybatis(持续更新)

    一 MyBatis相关概念回顾 1 对象 关系数据库映射 ORM ORM 全称Object Relation Mapping 表示对象 关系映射的缩写 ORM 完成面向对象的编程语言到关系数据库的映射 它把关系数据库包装成面向对象的模型 采
  • 网格搜索多个监督学习模型上的超参数,包括神经网络、随机森林和树集合模型(Matlab代码实现)

    目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码 1 概述 我们在选择超参数有两个途径 1 凭经验 2 选择不同大小的参数 带入到模型中 挑选表现最好的参数 通过途径2选择超参数时 人力手动调节注意力成本太高 非常不值得 F
  • 什么是环境变量?为什么java要配置环境变量?

    本文是将https blog csdn net qq 37872792 article details 80642985 与 https blog csdn net Pre waist L article details 79696507两
  • 虚拟机打开防火墙端口相关指令

    本篇文章用于记录在虚拟机操作过程中对于查看防火墙状态 开启防火墙 关闭防火墙指令进行记录 查看防火墙状态 systemctl status firewalld 开启防火墙 systemctl start firewalld 关闭防火墙 sy
  • 40 个 常用的 SpringBoot 注解,你知道几个?

    一 Spring Web MVC 与 Spring Bean 注解 Spring Web MVC 注解 RequestMapping RequestMapping注解的主要用途是将Web请求与请求处理类中的方法进行映射 Spring MVC
  • eNSP——VLAN配置实验

    目录 一 新建拓扑 二 配置LSW5 三 配置LSW6 一 新建拓扑 实现效果 PC10可以ping通PC12 ping不通PC11 PC13 二 配置LSW5 1 系统视图开启VLAN100 2 进入接口G0 0 1配置VLAN acce
  • signature=b05c505286f606b32d69ab58ee3e7bf4,reduce-css-calc/yarn.lock at 0f6c532cf9dc52ac3cb23e143eaf...

    THIS IS AN AUTOGENERATED FILE DO NOT EDIT THIS FILE DIRECTLY yarn lockfile v1 ava babel preset stage 4 1 0 0 version 1 1
  • 云计算之你必须知道的几个会议和杂志

    云计算现在被大家炒的热火朝天 那么很多人也想更多了解云计算 那么我就给大家介绍几个杂志和网站 IEEE International Conference on Cloud Computing http www thecloudcomputi
  • vue中的promise对象,async和await学习记录

    promise有待学习 先记录一下最近再项目中学的关于async和await async await 其实就是用同步的写法去实现异步方法 async deleteproduct record const result await produ
  • npm 配置淘宝镜像

    首先解释一下 npm 为什么要配置淘宝镜像 原因 因为node js 默认使用的是国外的网站 国内访问有一个跨国内局域网的操作 所以就会有时候很慢 这就跟为什么网站的静态资源有些会使用CDN 加速一样的 淘宝镜像是什么 就是npm 很多的插
  • hive转义问题详解

    hive转义问题详解 引言 hive控制台执行 字符串不包含 字符串包含 hive e的方式嵌入到shell脚本执行 字符串不包含 字符串包含 总结 引言 hive转义问题想必进来的同学都遇到过 这里就直奔主题了 此类问题大致可以分为两种常
  • Linux上快速安装软RAID详细步骤

    常见问题服务平台 2018 11 17 物理环境 虚拟机CentOS6 4 配置 8G内存 2 2核cpu 3块虚拟硬盘 sda sdb sdc sdb和sdc是完全一样的 在实际生产环境中 系统硬盘与数据库和应用是分开的 这样有利于系统的
  • HDRP

    HDRP 的 10 版本支持 Unity 2020 LTS 及以上 新版的 HDRP 软件包将继续优化用户友好的界面 灵活的功能 管线的稳定性和总体性能 但如果想将 HDRP 设置到最佳状态 你必须要了解所有主要的管线设置 及其背后的原理和
  • Oracle报错:IO Error: The Network Adapter could not establish the connection

    Caused by oracle net ns NetException The Network Adapter could not establish the connection at oracle net nt ConnStrateg
  • 深度学习框架Pytorch快速开发与实践

    决定用两个星期读完这本书 并自己用Pytorch搭建一个模型 2019 8 5 第一章深度学习介绍 明确学习目标 深度学习难点不是深度学习本身 难的是你要吃透问题 如何用深度学习的逻辑去思考你自己的问题 有针对性地设计模型 难的是你有分析问
  • 机器学习系列(7)_机器学习路线图(附资料)

    作者 龙心尘 寒小阳 时间 2016年2月 出处 http blog csdn net longxinchen ml article details 50749614 http blog csdn net han xiaoyang arti
  • epoll高度封装reactor,几乎所有可见服务器的底层框架

    目录 前言 reactor是什么 如何理解 reactor所需组件流程分析 组件 流程 如何将epoll的IO驱动封装成reactor事件反应堆驱动 reactor分块分析实现 注册事件处理器部分流程 多路复用器监视多路IO事件 事件分发器
  • 【React学习】React更新渲染原理

    当我们调用 setState 之后发生了什么 react经历了怎样的过程将新的 state 渲染到页面上 一次react更新 核心就是对虚拟dom进行diff 找出最少的需要变化的dom节点 然后对其进行相应的dom操作 用户即可在页面上看