react源码中的fiber架构
先看一下FiberNode
在源码中的样子
FiberNode
// packages/react-reconciler/src/ReactFiber.old.js
function FiberNode(tag: WorkTag, pendingProps: mixed, key: null | string, mode: TypeOfMode,
) {// Instancethis.tag = tag;this.key = key;this.elementType = null;this.type = null;this.stateNode = null;// Fiberthis.return = null;this.child = null;this.sibling = null;this.index = 0;this.ref = null;this.pendingProps = pendingProps;this.memoizedProps = null;this.updateQueue = null;this.memoizedState = null;this.dependencies = null;this.mode = mode;// Effectsthis.flags = NoFlags;this.nextEffect = null;this.firstEffect = null;this.lastEffect = null;this.lanes = NoLanes;this.childLanes = NoLanes;this.alternate = null;if (enableProfilerTimer) {// Note: The following is done to avoid a v8 performance cliff.//// Initializing the fields below to smis and later updating them with// double values will cause Fibers to end up having separate shapes.// This behavior/bug has something to do with Object.preventExtension().// Fortunately this only impacts DEV builds.// Unfortunately it makes React unusably slow for some applications.// To work around this, initialize the fields below with doubles.//// Learn more about this here:// https://github.com/facebook/react/issues/14365// https://bugs.chromium.org/p/v8/issues/detail?id=8538this.actualDuration = Number.NaN;this.actualStartTime = Number.NaN;this.selfBaseDuration = Number.NaN;this.treeBaseDuration = Number.NaN;// It's okay to replace the initial doubles with smis after initialization.// This won't trigger the performance cliff mentioned above,// and it simplifies other profiler code (including DevTools).this.actualDuration = 0;this.actualStartTime = -1;this.selfBaseDuration = 0;this.treeBaseDuration = 0;}if (__DEV__) {// This isn't directly used but is handy for debugging internals:...}
}
- 我们看
FiberNode
这个构造函数里面只是赋值,我们再找一下链路上的Fiber
,我们发现在函数createFiber
的返回值类型里面出现了Fiber
类型,所以
// packages/react-reconciler/src/ReactInternalTypes.js
export type Fiber = {|// These first fields are conceptually members of an Instance. This used to// be split into a separate type and intersected with the other Fiber fields,// but until Flow fixes its intersection bugs, we've merged them into a// single type.// An Instance is shared between all versions of a component. We can easily// break this out into a separate object to avoid copying so much to the// alternate versions of the tree. We put this on a single object for now to// minimize the number of objects created during the initial render.// dom节点的相关信息tag: WorkTag,// 组件的类型key: null | string, // 唯一值elementType: any,// 元素类型// 判定fiber节点的类型,用于difftype: any,// 真实 dom 节点stateNode: any,// Conceptual aliases// parent : Instance -> return The parent happens to be the same as the// return fiber since we've merged the fiber and instance.// Remaining fields belong to Fiber// fiber 链表树return: Fiber | null, // 父 fiberchild: Fiber | null, // 第一个子 fibersibling: Fiber | null, // 下一个兄弟 fiberindex: number, // 在父 fiber 下面的子 fiber 中的下标// The ref last used to attach this node.// I'll avoid adding an owner field for prod and model that as functions.ref:| null| (((handle: mixed) => void) & {_stringRef: ?string, ...})| RefObject,// 计算 state 和 props 渲染pendingProps: any, // 本次渲染需要使用的 propsmemoizedProps: any, // 上次渲染使用的 propsupdateQueue: mixed, // 用于状态更新、回调函数、DOM更新的队列memoizedState: any, // 上次渲染后的 state 状态dependencies: Dependencies | null, // contexts、events 等依赖// Bitfield that describes properties about the fiber and its subtree. E.g.// the ConcurrentMode flag indicates whether the subtree should be async-by-// default. When a fiber is created, it inherits the mode of its// parent. Additional flags can be set at creation time, but after that the// value should remain unchanged throughout the fiber's lifetime, particularly// before its child fibers are created.mode: TypeOfMode,// Effectflags: Flags, // 记录更新时当前 fiber 的副作用(删除、更新、替换等)状态subtreeFlags: Flags, // 当前子树的副作用状态deletions: Array<Fiber> | null, // 要删除的子 fibernextEffect: Fiber | null, // 下一个有副作用的 fiberfirstEffect: Fiber | null, // 指向第一个有副作用的 fiberlastEffect: Fiber | null, // 指向最后一个有副作用的 fiber // 渲染优先级lanes: Lanes,childLanes: Lanes,// This is a pooled version of a Fiber. Every fiber that gets updated will// eventually have a pair. There are cases when we can clean up pairs to save// memory if we need to.alternate: Fiber | null,// 指向 workInProgress fiber 树中对应的节点// Time spent rendering this Fiber and its descendants for the current update.// This tells us how well the tree makes use of sCU for memoization.// It is reset to 0 each time we render and only updated when we don't bailout.// This field is only set when the enableProfilerTimer flag is enabled.actualDuration?: number,// If the Fiber is currently active in the "render" phase,// This marks the time at which the work began.// This field is only set when the enableProfilerTimer flag is enabled.actualStartTime?: number,// Duration of the most recent render time for this Fiber.// This value is not updated when we bailout for memoization purposes.// This field is only set when the enableProfilerTimer flag is enabled.selfBaseDuration?: number,// Sum of base times for all descendants of this Fiber.// This value bubbles up during the "complete" phase.// This field is only set when the enableProfilerTimer flag is enabled.treeBaseDuration?: number,// Conceptual aliases// workInProgress : Fiber -> alternate The alternate used for reuse happens// to be the same as work in progress.// __DEV__ only_debugID?: number,_debugSource?: Source | null,_debugOwner?: Fiber | null,_debugIsCurrentlyTiming?: boolean,_debugNeedsRemount?: boolean,// Used to verify that the order of hooks does not change between renders._debugHookTypes?: Array<HookType> | null,
|};
相关参考视频讲解:进入学习
- 整个fiber架构看起来可以分为dom信息、副作用、优先级、链表树等几个模块,那我们依次来拆分一下
dom信息节点
tag: WorkTag
我们看到这个`tag`为`WorkTag`类型,用来区分`React`组件的类型
// packages/react-reconciler/src/ReactWorkTags.js
export type WorkTag =| 0| 1| 2| 3| 4| 5| 6| 7| 8| 9| 10| 11| 12| 13| 14| 15| 16| 17| 18| 19| 20| 21| 22| 23| 24;export const FunctionComponent = 0;
export const ClassComponent = 1;
export const IndeterminateComponent = 2; // Before we know whether it is function or class
export const HostRoot = 3; // Root of a host tree. Could be nested inside another node.
export const HostPortal = 4; // A subtree. Could be an entry point to a different renderer.
export const HostComponent = 5;
export const HostText = 6;
export const Fragment = 7;
export const Mode = 8;
export const ContextConsumer = 9;
export const ContextProvider = 10;
export const ForwardRef = 11;
export const Profiler = 12;
export const SuspenseComponent = 13;
export const MemoComponent = 14;
export const SimpleMemoComponent = 15;
export const LazyComponent = 16;
export const IncompleteClassComponent = 17;
export const DehydratedFragment = 18;
export const SuspenseListComponent = 19;
export const FundamentalComponent = 20;
export const ScopeComponent = 21;
export const Block = 22;
export const OffscreenComponent = 23;
export const LegacyHiddenComponent = 24;
上述代码,区分了组件的类型,在后期协调阶段beginWork
、completeWork
的流程里根据不同的类型组件去做不同的fiber
节点的处理
key: null | string、type: any
key为唯一值,type为与fiber关联的节点类型,都用于beginWork流程里面的reconcileChildren流程
elementType
元素类型
stateNode
- stateNode 用于记录当前 fiber 所对应的真实 dom 节点或者当前虚拟组件的实例。
- 便于实现Ref
- 便于追踪Rdom
fiber 链表树
fiber
链表树里面有四个字段return
、child
、sibling
、index
- return:指向父节点,没有父节点则为null。
- child:指向下一个子节点,没有下一个子节点则为null。
- sibling:指向兄弟节点,没有下一个兄弟节点则为null。
- index:父fiber下面的子fiber下标
通过这些字段那么我们可以形成一个闭环链表,举个栗子。
<div className='box'><h1 className='title' style={{'color':'red'}}>React源码解析</h1><ul><li>第一章</li><li>第二章</li><li>第三章</li><li>第四章</li></ul>
</div>
根据上面的代码所对应的fiber链表树结构就是:
副作用相关
所谓副作用就是一套流程中我们不期望发生
的情况。举个通俗的例子就是我们生活中去学游泳
,在学会游泳的过程中呛了几口水
,这个呛了几口水
相对于成功学会游泳来说就是副作用
,回归到react
代码中,我们通过某些手段去修改props
、state
等数据,数据修改完毕之后,但是同时引起了dom不必要的变化
,那么这个变化就是副作用
,当然这个副作用是必然存在的
,就像游泳一样,必然会呛几口水,哈哈。
flags: Flags
记录当前节点通过`reconcileChildren`之后的的副作用,如插入,删除等
例如Placement
,表示插入,也叫新增。Deletion
表示删除,Update
表示更新
export type Flags = number;// Don't change these two values. They're used by React Dev Tools.
export const NoFlags = /* */ 0b000000000000000000;
export const PerformedWork = /* */ 0b000000000000000001;// You can change the rest (and add more).
export const Placement = /* */ 0b000000000000000010;
export const Update = /* */ 0b000000000000000100;
export const PlacementAndUpdate = /* */ 0b000000000000000110;
export const Deletion = /* */ 0b000000000000001000;
export const ContentReset = /* */ 0b000000000000010000;
export const Callback = /* */ 0b000000000000100000;
export const DidCapture = /* */ 0b000000000001000000;
export const Ref = /* */ 0b000000000010000000;
export const Snapshot = /* */ 0b000000000100000000;
export const Passive = /* */ 0b000000001000000000;
// TODO (effects) Remove this bit once the new reconciler is synced to the old.
export const PassiveUnmountPendingDev = /* */ 0b000010000000000000;
export const Hydrating = /* */ 0b000000010000000000;
export const HydratingAndUpdate = /* */ 0b000000010000000100;// Passive & Update & Callback & Ref & Snapshot
export const LifecycleEffectMask = /* */ 0b000000001110100100;// Union of all host effects
export const HostEffectMask = /* */ 0b000000011111111111;// These are not really side effects, but we still reuse this field.
export const Incomplete = /* */ 0b000000100000000000;
export const ShouldCapture = /* */ 0b000001000000000000;
export const ForceUpdateForLegacySuspense = /* */ 0b000100000000000000;// Static tags describe aspects of a fiber that are not specific to a render,
// e.g. a fiber uses a passive effect (even if there are no updates on this particular render).
// This enables us to defer more work in the unmount case,
// since we can defer traversing the tree during layout to look for Passive effects,
// and instead rely on the static flag as a signal that there may be cleanup work.
export const PassiveStatic = /* */ 0b001000000000000000;// Union of side effect groupings as pertains to subtreeFlags
export const BeforeMutationMask = /* */ 0b000000001100001010;
export const MutationMask = /* */ 0b000000010010011110;
export const LayoutMask = /* */ 0b000000000010100100;
export const PassiveMask = /* */ 0b000000001000001000;// Union of tags that don't get reset on clones.
// This allows certain concepts to persist without recalculting them,
// e.g. whether a subtree contains passive effects or portals.
export const StaticMask = /* */ 0b001000000000000000;// These flags allow us to traverse to fibers that have effects on mount
// without traversing the entire tree after every commit for
// double invoking
export const MountLayoutDev = /* */ 0b010000000000000000;
export const MountPassiveDev = /* */ 0b100000000000000000;
当然副作用不仅仅只是一个,所以React
中在render
阶段中采用的是深度遍历
的策略去找出当前fiber树中所有的副作用,并维护一个副作用链表EffectList
,与链表相关的字段还有firstEffect
、nextEffect
和 lastEffect
我们来画一张图来简略示意一下。
解读一下就是,fristEffect
指向第一个有副作用的fiber
节点,lastEffect
指向最后一个具有副作用的fiber
节点,中间都是用nextEffect
链接,这样组成了一个单向链表。
render阶段里面这一段处理就完了,在后面的commit
阶段里面,React
会根据EffectList
里面fiber
节点的副作用,会对应的处理相应的DOM
,然后生成无副作用的虚拟节点
,进行真实dom
的创建。
优先级相关
当然React
作为一个庞大的框架,肯定有自己的一套关于渲染的优先级机制,不然全都是一股脑按部就班
的走,那肯定不行哒。
那么优先级我们就要关注一下lane
与alternate
,React
中每个fiber
任务都有自己的lane(执行优先级)
,这样在render
阶段react
才知道,应该优先把哪个fiber
任务提交到commit
阶段去执行。而alternate
是在render
阶段中用来做为指针的,什么意思?React
在状态发生改变的时候,就会根据当前的页面结构
,生成两棵fiber树
,一棵老的称之为current Fiber
,而另一棵将要生成新的页面的树
叫做workInProgress Fiber
,而alternate
作为指针,就是把current Fiber
中的每一个节点指向workInProgress Fiber
中的每一个节点。同样的他也会从workInProgress Fiber
中指向 current Fiber
我们了解到了alternate
,那就来说一说这个lane
吧。
// packages/react-reconciler/src/ReactFiberLane.js
export const NoLanes: Lanes = /* */ 0b0000000000000000000000000000000;
export const NoLane: Lane = /* */ 0b0000000000000000000000000000000;export const SyncLane: Lane = /* */ 0b0000000000000000000000000000001;
export const SyncBatchedLane: Lane = /* */ 0b0000000000000000000000000000010;export const InputDiscreteHydrationLane: Lane = /* */ 0b0000000000000000000000000000100;
const InputDiscreteLanes: Lanes = /* */ 0b0000000000000000000000000011000;const InputContinuousHydrationLane: Lane = /* */ 0b0000000000000000000000000100000;
const InputContinuousLanes: Lanes = /* */ 0b0000000000000000000000011000000;export const DefaultHydrationLane: Lane = /* */ 0b0000000000000000000000100000000;
export const DefaultLanes: Lanes = /* */ 0b0000000000000000000111000000000;const TransitionHydrationLane: Lane = /* */ 0b0000000000000000001000000000000;
const TransitionLanes: Lanes = /* */ 0b0000000001111111110000000000000;const RetryLanes: Lanes = /* */ 0b0000011110000000000000000000000;export const SomeRetryLane: Lanes = /* */ 0b0000010000000000000000000000000;export const SelectiveHydrationLane: Lane = /* */ 0b0000100000000000000000000000000;const NonIdleLanes = /* */ 0b0000111111111111111111111111111;export const IdleHydrationLane: Lane = /* */ 0b0001000000000000000000000000000;
const IdleLanes: Lanes = /* */ 0b0110000000000000000000000000000;export const OffscreenLane: Lane = /* */ 0b1000000000000000000000000000000;
可见这个lane也是用31位二进制表示的唯一值,来进行优先级的判定的,并且位数越低,则优先级越大。
Props && State相关
pendingProps: any
本次渲染需要使用的 props
memoizedProps: any
上次渲染使用的 props
updateQueue: mixed
用于状态更新、回调函数、DOM更新的队列
memoizedState: any
上次渲染后的 state 状态
dependencies: Dependencies | null
contexts、events 等依赖
Fiber树的创建与更新的流程
上面一部分讲了React Fiber
的基本架构,从真实dom信息
、副作用
、优先级
等方面看了一下,为后面的render阶段
的协调
与调度
以及commit阶段
打下基础,那么接下来我们去探讨一下new FiberNode
之后得到的什么样的rootFiber
。
我们在第二章节里面提到了整个的创建过程# React源码解析系列(二) – 初始化组件的创建更新流程,那么这里深入探讨一下createFiber
,在这个函数里面new FiberNode
,创建了rootFiber
,他也就是整个React
应用的的根fiber
。并且在createFiberRoot
里面new FiberRootNode
,创建了fiberRoot
,它便是指向真实dom的根节点
。所以在# React源码解析系列(二) – 初始化组件的创建更新流程中我强调了root.current
、uninitializedFiber.stateNode
这两个东西,也就是这里说的rootFiber
的stateNode
字段指向了 fiberRoot
,并且fiberRoot的current
指向了rootFiber
,具体的示例图如下:
所以这里就完成了fiber
树根节点的创建了。
拿到了上面创建完成的rootFiber
和fiberRoot
之后那么我们接下来就是去根据我们的组件jsx
去创建详细的dom
树了,举个例子:
<div className='box'><h1 className='title' style={{'color':'red'}}>React源码解析</h1><ul><li>第一章</li><li>第二章</li><li>第三章</li><li>第四章</li></ul>
</div>
现有上面的jsx
,那么我们创建dom
树的形式是深度优先遍历,已beginwork
和completework
表示一个节点的创建过程,流程如下:
上面的图说明了,在初始化的时候我们的dom
树是怎么被创建出来的,那么在状态发生改变的时候,我们会根据当前新的jsx
内容创建新的workInProgress fiber
,我们以新的jsx
为例:
<div className='box'>
<h1 className='title' style={{'color':'red'}}>React源码解析</h1>
+ <h1 className='title' style={{'color':'red'}}>React源码解析系列</h1><ul><li>第一章</li><li>第二章</li><li>第三章</li>
- <li>第四章</li></ul>
+ <p>总结</p>
</div>
上面的jsx
表示,更改了h1
的内容,删除了第四章,增加了总结这几个操作,那么react
根据当前新的jsx
调用createWorkInProgress
方法创建workInProgress fiber
,那么我们先去看一下createWorkInProgress
的源码实现。
export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {let workInProgress = current.alternate;if (workInProgress === null) { // null为初始化,否为update// We use a double buffering pooling technique because we know that we'll// only ever need at most two versions of a tree. We pool the "other" unused// node that we're free to reuse. This is lazily created to avoid allocating// extra objects for things that are never updated. It also allow us to// reclaim the extra memory if needed.workInProgress = createFiber(current.tag,pendingProps,current.key,current.mode,);workInProgress.elementType = current.elementType;workInProgress.type = current.type;workInProgress.stateNode = current.stateNode;if (__DEV__) {// DEV-only fieldsworkInProgress._debugID = current._debugID;workInProgress._debugSource = current._debugSource;workInProgress._debugOwner = current._debugOwner;workInProgress._debugHookTypes = current._debugHookTypes;}// current 指向 workInProgressworkInProgress.alternate = current;// workInProgress 指向 currentcurrent.alternate = workInProgress;} else {// 上一次的propsworkInProgress.pendingProps = pendingProps;// Needed because Blocks store data on type.workInProgress.type = current.type;// We already have an alternate.// Reset the effect tag.//清除flagsworkInProgress.flags = NoFlags;// The effect list is no longer valid.workInProgress.nextEffect = null;workInProgress.firstEffect = null;workInProgress.lastEffect = null;if (enableProfilerTimer) {// We intentionally reset, rather than copy, actualDuration & actualStartTime.// This prevents time from endlessly accumulating in new commits.// This has the downside of resetting values for different priority renders,// But works for yielding (the common case) and should support resuming.workInProgress.actualDuration = 0;workInProgress.actualStartTime = -1;}}// 绑定挂载的子fiber节点优先级、状态、propsworkInProgress.childLanes = current.childLanes;workInProgress.lanes = current.lanes;workInProgress.child = current.child;workInProgress.memoizedProps = current.memoizedProps;workInProgress.memoizedState = current.memoizedState;workInProgress.updateQueue = current.updateQueue;// Clone the dependencies object. This is mutated during the render phase, so// it cannot be shared with the current fiber.const currentDependencies = current.dependencies;workInProgress.dependencies =currentDependencies === null? null: {lanes: currentDependencies.lanes,firstContext: currentDependencies.firstContext,};// These will be overridden during the parent's reconciliationworkInProgress.sibling = current.sibling;workInProgress.index = current.index;workInProgress.ref = current.ref;if (enableProfilerTimer) {workInProgress.selfBaseDuration = current.selfBaseDuration;workInProgress.treeBaseDuration = current.treeBaseDuration;}if (__DEV__) {workInProgress._debugNeedsRemount = current._debugNeedsRemount;switch (workInProgress.tag) {case IndeterminateComponent:case FunctionComponent:case SimpleMemoComponent:workInProgress.type = resolveFunctionForHotReloading(current.type);break;case ClassComponent:workInProgress.type = resolveClassForHotReloading(current.type);break;case ForwardRef:workInProgress.type = resolveForwardRefForHotReloading(current.type);break;default:break;}}return workInProgress;
}
并且为其标记副作用,具体如下:
而前面所说的alternate在这里相互指向,其实也就是在reconciler
阶段起到了复用节点的作用,因为我们所说的current fiber
或者是workInProgress fiber
都是视图的产物,是可以在"新"与"老"之间转换的。
为什么会出现Fiber架构呢?
相信在座的各位写React的同学出去面试,面试官总会问:”请问你知道React Fiber架构吗?请你说说Fiber架构吧“
为什么会出现?通过上面的React Fiber
架构的讲解,我们可以get
到几个点,那就是fiber
针对每一个fiber
节点都会有一套自己的独立的beginwork
和completework
,并且能够在每一个具有副作用
的节点上进行打标处理,而不是直接变更。而且生成的current fiber
与workIProgress fiber
可以相互转换,这里间接地可以称之为缓存吧。对比与以前的React
应用来讲,以前的React
应用是根据执行生命周期
、diff
、dom的更新
一套流程同步走的,一套流程下来,不能中断,而且每一次的更新都是从根节点出发向下遍历的,我们可以设想一下处理庞大的结构的时候,那将是不可想象的性能开销
,处理长时间任务耗时更长,更重要的是用户的交互,事件得不到及时响应,用户体验非常的差。
但是fiber
这种结构,我们说的是一种时间分片
的概念,通过时间分片把长任务,分成一个个独立的小单元
去执行,返回。这样子就不会让js线程
被React应用
独占,能有有空余去处理其他优先级较高
的任务,任务得到了相应并且执行,当然了这种情况下页面就不会显得卡顿了。
所以总结来说就是React Fiber
给我们提供了一种协调
,调度
,暂停
,中止
,调优
的方式去更好的处理React应用
与浏览器
的工作,保证了页面的性能与流畅度
总结
这一章讲述了整个的fiber架构与fiber树的创建与更新,那么这里从React应用的初始化挂载到React更新就形成了一部分的闭环完结,之后我们便是沿着流程走到了updateContainer
更新这里
相关文章:

react源码中的fiber架构
先看一下FiberNode在源码中的样子 FiberNode // packages/react-reconciler/src/ReactFiber.old.js function FiberNode(tag: WorkTag, pendingProps: mixed, key: null | string, mode: TypeOfMode, ) {// Instancethis.tag tag;this.key key;this.elementType null;t…...

C++类和对象-继承多态
继承 继承是面向对象三大特性之一 定义类时,下级别的成员除了拥有上一级的共性,还有自己的特性,就可以考虑使用继承的技术,减少代码的重复 继承的基本语法 语法:class 子类 : 继承方式 父类 子类也被成为派生类父类…...

appium自动化测试
获取应用包名和入口activity:aapt命令 aapt目录: 安卓sdk的build-tools目录下(如果要在cmd里直接运行,要配置环境变量,否则需要在aapt所在目录下打开cmd) 示例: adt-bundle-windows-x86_64-20140702\sdk\build-too…...

打印流、转换流、数据流 、随机访问流
Java知识点总结:想看的可以从这里进入 目录5、打印流6、转换流7、数据流8、随机访问流5、打印流 实现将基本数据类型的数据格式转化为字符串输出,它们提供了一系列重载的print()和println()方法,用于多种数据类型的输出,这种流不会…...
Java的4种访问权限?
1、public: 所修饰的类、变量、方法,在内外包均具有访问权限;2、protected: 这种权限是为继承而设计的,protected所修饰的成员,对所有子类是可访问的,但只对同包的类是可访问的,对外…...

APP任务模块功能借助php-resque实现业务解耦
先上设计图 说明:任务模块分一次性任务和每日任务,可能还包括男女用户任务区分 处理步骤: 一、同步任务数据库 1.1、任务列表数据库 1.2、完成任务数据库 二、搭建即时消息队列 一、composer require resque/php-resque二、因为服务器red…...
怎么做,才能在职场中晋升?
1 主动原则:主动做事 工作要积极主动,刚进入职场的同学,以为“服从命令听指挥”“领导指哪打哪”就是积极主动,结果易养 1.1 不好习惯 ① 认为主管肯定会帮你搞定晋升 你可能非常信任主管,认为自己只要把主管安排的…...

Vulnhub靶场----2、DC-2
文章目录一、环境搭建二、渗透流程三、思路总结一、环境搭建 DC-2下载地址:https://download.vulnhub.com/dc/DC-2.zip kali:192.168.144.148 DC-2:192.168.144.150 添加hosts文件:192.168.144.150 DC-2 二、渗透流程 nmap -A -…...

Java 基础(3)—synchornized 关键字简单理解
一、synchronized 修饰同步代码块 用 synchronized 修饰代码段作为同步锁,代码如下: public class LockDemo {public Object object new Object();public void show(){synchronized (object) {System.out.println(">>>>>>hell…...

【Linux】调试工具gdb的使用
环境:centos7.6,腾讯云服务器Linux文章都放在了专栏:【Linux】欢迎支持订阅🌹前言在前文,我们已经讲解了vim工具以及gcc/g的使用,我们可以进行编写代码以及编译代码了,但是还没有学习如何在Linu…...

大数据知识图谱项目——基于知识图谱的医疗知识问答系统(详细讲解及源码)
基于知识图谱的医疗知识问答系统 一、项目概述 本项目基于医疗方面知识的问答,通过搭建一个医疗领域知识图谱,并以该知识图谱完成自动问答与分析服务。本项目以neo4j作为存储,基于传统规则的方式完成了知识问答,并最终以关键词执…...

威马汽车:跃马扬鞭未竟,鞍马劳顿难行?
“活下去,像牲口一样地活下去。” 威马汽车创始人、董事长兼CEO沈晖1月在社交媒体上分享的电影台词,已然成为威马近况的真实写照。 来源:新浪微博威马汽车沈晖Freeman 最近,网上出现了大量关于“威马汽车将实施全员停薪留职”的…...

【网络】网络基础
🥁作者: 华丞臧. 📕专栏:【网络】 各位读者老爷如果觉得博主写的不错,请诸位多多支持(点赞收藏关注)。如果有错误的地方,欢迎在评论区指出。 推荐一款刷题网站 👉 LeetCode刷题网站 文章…...
Linux系统之Uboot、Kernel、Busybox思考之三
目录 三 内核的运行 5-中断子系统 6 锁、延迟与原子上下文 7 内存管理子系统 8 驱动的两类框架 三 内核的运行 5-中断子系统 中断子系统的数据结构及设计思想。 中断子系统需要解决中断管理的问题。 如果系统中断较少的话,其管理就不用设计这样一个中断子系统这…...

FPGA 20个例程篇:20.USB2.0/RS232/LAN控制并行DAC输出任意频率正弦波、梯形波、三角波、方波(一)
在最后一个例程中笔者精挑细选了一个较为综合性的项目实战,其中覆盖了很多知识点,也是从一个转产产品中所提炼出来的,所以非常贴近实战项目。 整个工程实现了用户通过对上位机PC端人机界面的操作,即可达到控制豌豆开发并行DAC输出…...

性能测试学习和性能瓶颈分析路线
很多企业招聘都只写性能测试,会使用LR,jmeter工具。其实会使用jmeter和LR进行性能测试还只是性能测试的第一步,离真正的性能测试工程师还很远,笔者也还在路上 .。 性能测试,都是要求测试系统性能,系统自然…...

达梦数据库(DM8)集成使用 Geoserver(2.22.2) 以及其他对应版本详解
达梦数据库(DM8)集成使用 Geoserver(2.22.2) 以及其他对应版本详解系统环境版本Geoserver 驱动对应版本达梦 8 集成 Geoserver 过程试错过程问题总结项目需要国产化,选择使用达梦数据库,在技术测试阶段&…...

全开源无加密的RuleApp文章社区APP客户端源码
内容目录一、详细介绍二、效果展示1.部分代码2.效果图展示三、学习资料下载一、详细介绍 开源无加密的文章社区客户端源码分享 RuleApp文章社区,VIP会员,写作投稿积分商城,付费模块集成,多平台兼容这是一款开源免费,界…...

基于springboot校园二手市场平台
一、项目简介 本项目是一套基于springboot校园二手市场平台,主要针对计算机相关专业的正在做bishe的学生和需要项目实战练习的Java学习者。 包含:项目源码、数据库脚本等,该项目可以直接作为bishe使用。 项目都经过严格调试,确保…...

维度建模基本流程总结
一、维度建模基本流程图数据RD进行业务调研和数据现状调研,产出符合相关模版规范的业务知识文档和数据现状文档。数据PM也会调研相关业务产出需求设计文档,三方参与需求评审,评审通过后基建数据RD进行需求拆解,产出技术方案&#…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...

Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...

Vue ③-生命周期 || 脚手架
生命周期 思考:什么时候可以发送初始化渲染请求?(越早越好) 什么时候可以开始操作dom?(至少dom得渲染出来) Vue生命周期: 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...