React16源码: React中的renderRoot的源码实现
renderRoot
1 )概述
renderRoot
是一个非常复杂的方法- 这个方法里处理很多各种各样的逻辑, 它主要的工作内容是什么?
- A. 它调用
workLoop
进行循环单元更新- 遍历整个 Fiber Tree,把每一个组件或者 dom 节点对应的
- Fiber 节点拿出来单一的进行更新,这是一个循环的操作
- 把整棵 Fiber Tree 都遍历一遍,这就是
workLoop
- B. 捕获错误并进行处理
- 在进行每一个单元更新的时候,这个遍历逻辑的时候,有可能会出现一些错误
- 有些是可预期的,比如说是 Suspense 的功能, throw 一个 Promise 对象
- 这个时候,是我们要特殊的对它进行处理的
- 有一些是不可预期的,比如说, render 里面报了一个错误
- 我们也要对它进行一些处理,要告诉我们的react这个地方
- 我们出现了一个错误,在react16之后,有了
Error Boundary
- 可以在组件内捕获渲染的错误
- C. 在走完流程之后要进行善后
- 因为流程走完之后会有各种不同的情况
- 比如说有错误的情况,比如说有任务被挂起的情况,也就是Suspense的情况
- 这些任务,都要按照特定的逻辑给它进行一些处理
- 这就是
renderRoot
这个方法,它的主要的核心工作内容
2 )流程图

- 进入 renderRoot, 它里面有一个很核心的循环
do while workLoop
- 这个while循环就是调用 workLoop 对整棵树,它每个节点进行一个遍历,并且拿出来单独进行更新
- 因为每个 Fiber节点上,如果有更新的话,它会记入 updateQueen
- 我们通过 updateQueen 上是否有内容来判断它是否要进行更新
- 以及可以计算出它的新的 state,得到最新的 children,拿到所有最新的节点
- 在 workLoop 的过程当中,它在做什么呢?
nextUnitOfWork
就是每一个节点在遍历的过程当中,它自己更新完之后,它会返回它的第一个child- 它的第一个child 就是作为 nextUnitOfWork,因为我们执行了一个节点的更新之后,我们需要返回
- 返回之后,我们要判断一些逻辑
- 比如,对于异步的操作,每个节点更新完之后都要判断
!shouldYield()
- 判断我们现在的时间片是否还有?如果还有的话,再继续,如果没有的话,就要跳出了
- 接下去就会执行
performUnitOfWork
- 之后,执行
beginWork
,completeUnitOfWork
这些,当然中间会判断是否有 next - next就是我在更新完一个结点之后,它是否还有下一个节点需要更新
- 如果有next的情况,我们就返回,然后去判断这个逻辑是否还有
- 这就是整个对整个 fiber tree 每个节点的遍历更新
- 在这个更新过程当中,如果有任何catch,就是捕获到异常
- 那么首先会进行一系列的判断,然后对它执行 throwException 或者是 onUncaughtError
- 它们对应的逻辑会不一样, 如果这个节点它是可处理的错误
- 我会直接对它进行
completeUnitOfWork()
因为更新到这个节点之后,它抛出错误了 - 说明我们这个节点下面的所有子节点都不需要再更新了
- 执行完成之后,我们就会调用 continue,对于这个 do while 循环,它又继续调用 workLoop
- 也就是说我们把一棵子数的错误处理完之后,它还可以继续对别的子树进行更新
- 整体更新完之后,就会 break,之后会有各种不同的情况,比如说有致命的错误等
- 它们都会调用不同的逻辑进行一个处理,这里
nextRenderDidError
是一个可处理的错误 - 比如说, 是可以被捕获的错误,有组件能捕获它,而
nextLatestAbsoluteTimeoutMs
是抛出promise的错误 - 它是一个被挂起的一个任务,对应要执行一个被被挂起的操作, 最后如果上面的情况都没有出现
- 直接
onComplete
,之后就可以在root节点上set finishedwork
,这样, 就可以对它整体进行一个更新 - 就可以执行
completeRoot
,就可以把 fiber树 变成我们真正的dom 树去更新整个页面 - 这就是整个 renderRoot 它的一个逻辑,简单总结
- 先正常的执行每个单元的更新
- 然后捕获到任何错误进行一定的处理
- 最终把整个树遍历完之后根据不同的情况再进行一个处理
3 )源码
定位到 packages/react-reconciler/src/ReactFiberScheduler.js
先看 renderRoot 的代码
function renderRoot(root: FiberRoot,isYieldy: boolean,isExpired: boolean,
): void {invariant(!isWorking,'renderRoot was called recursively. This error is likely caused ' +'by a bug in React. Please file an issue.',);isWorking = true;ReactCurrentOwner.currentDispatcher = Dispatcher;const expirationTime = root.nextExpirationTimeToWorkOn;// Check if we're starting from a fresh stack, or if we're resuming from// previously yielded work.// 刚进来的时候,进行这个判断// nextRoot 和 nextRenderExpirationTime 对应着接下来要渲染的节点和对应的过期时间 这是两个公共变量// 在这种情况下,说明调用这个方法的时候,接收到的参数和之前的不一样,可能就是之前的异步任务被新进来的高优先级的任务给打断了if (expirationTime !== nextRenderExpirationTime ||root !== nextRoot ||nextUnitOfWork === null) {// Reset the stack and start working from the root.resetStack();nextRoot = root;nextRenderExpirationTime = expirationTime;// nextUnitOfWork 来自于 createWorkInProgress// 就是把当前的应用的状态对应的Fiber节点,拷贝了一份叫做 workInProgress 的对象// 因为我们不能直接在当前对象的Fiber节点上操作,它会影响我们目前的dom节点展示的样子// 所以要复制一份拷贝,对拷贝进行操作,workInProgress 和 current 之间会有一个转换的关系// 在renderRoot开始之后,我们真正操作的节点都是 workInProgress,没有直接在 current 上操作nextUnitOfWork = createWorkInProgress(nextRoot.current,null,nextRenderExpirationTime,);// 这种和不同expirationTime会有关系root.pendingCommitExpirationTime = NoWork;if (enableSchedulerTracing) {// Determine which interactions this batch of work currently includes,// So that we can accurately attribute time spent working on it,// And so that cascading work triggered during the render phase will be associated with it.const interactions: Set<Interaction> = new Set();root.pendingInteractionMap.forEach((scheduledInteractions, scheduledExpirationTime) => {if (scheduledExpirationTime <= expirationTime) {scheduledInteractions.forEach(interaction =>interactions.add(interaction),);}},);// Store the current set of interactions on the FiberRoot for a few reasons:// We can re-use it in hot functions like renderRoot() without having to recalculate it.// We will also use it in commitWork() to pass to any Profiler onRender() hooks.// This also provides DevTools with a way to access it when the onCommitRoot() hook is called.root.memoizedInteractions = interactions;if (interactions.size > 0) {const subscriber = __subscriberRef.current;if (subscriber !== null) {const threadID = computeThreadID(expirationTime,root.interactionThreadID,);try {subscriber.onWorkStarted(interactions, threadID);} catch (error) {// Work thrown by an interaction tracing subscriber should be rethrown,// But only once it's safe (to avoid leaveing the scheduler in an invalid state).// Store the error for now and we'll re-throw in finishRendering().if (!hasUnhandledError) {hasUnhandledError = true;unhandledError = error;}}}}}}let prevInteractions: Set<Interaction> = (null: any);if (enableSchedulerTracing) {// We're about to start new traced work.// Restore pending interactions so cascading work triggered during the render phase will be accounted for.prevInteractions = __interactionsRef.current;__interactionsRef.current = root.memoizedInteractions;}let didFatal = false;startWorkLoopTimer(nextUnitOfWork);// 上面初始化工作做完之后,就开始 workLoop// 如果有 catch 就会有一大段处理逻辑, 这里先跳过// do {try {workLoop(isYieldy);} catch (thrownValue) {if (nextUnitOfWork === null) {// This is a fatal error.didFatal = true;onUncaughtError(thrownValue);} else {if (__DEV__) {// Reset global debug state// We assume this is defined in DEV(resetCurrentlyProcessingQueue: any)();}const failedUnitOfWork: Fiber = nextUnitOfWork;if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) {replayUnitOfWork(failedUnitOfWork, thrownValue, isYieldy);}// TODO: we already know this isn't true in some cases.// At least this shows a nicer error message until we figure out the cause.// https://github.com/facebook/react/issues/12449#issuecomment-386727431invariant(nextUnitOfWork !== null,'Failed to replay rendering after an error. This ' +'is likely caused by a bug in React. Please file an issue ' +'with a reproducing case to help us find it.',);const sourceFiber: Fiber = nextUnitOfWork;let returnFiber = sourceFiber.return;if (returnFiber === null) {// This is the root. The root could capture its own errors. However,// we don't know if it errors before or after we pushed the host// context. This information is needed to avoid a stack mismatch.// Because we're not sure, treat this as a fatal error. We could track// which phase it fails in, but doesn't seem worth it. At least// for now.didFatal = true;onUncaughtError(thrownValue);} else {throwException(root,returnFiber,sourceFiber,thrownValue,nextRenderExpirationTime,);nextUnitOfWork = completeUnitOfWork(sourceFiber);continue;}}}break;} while (true);if (enableSchedulerTracing) {// Traced work is done for now; restore the previous interactions.__interactionsRef.current = prevInteractions;}// We're done performing work. Time to clean up.isWorking = false;ReactCurrentOwner.currentDispatcher = null;resetContextDependences();// 在处理完 workLoop 后这里会有各种不同的判断// Yield back to main thread.// 这里代表有致命的错误if (didFatal) {const didCompleteRoot = false;stopWorkLoopTimer(interruptedBy, didCompleteRoot);interruptedBy = null;// There was a fatal error.if (__DEV__) {resetStackAfterFatalErrorInDev();}// `nextRoot` points to the in-progress root. A non-null value indicates// that we're in the middle of an async render. Set it to null to indicate// there's no more work to be done in the current batch.nextRoot = null;onFatal(root);return;}// 正常流程走完,这个if一定会匹配// 因为已经跳出 workLoop 了,说明一定有 react没有意识到的错误,所以调用 onYieldif (nextUnitOfWork !== null) {// There's still remaining async work in this tree, but we ran out of time// in the current frame. Yield back to the renderer. Unless we're// interrupted by a higher priority update, we'll continue later from where// we left off.const didCompleteRoot = false;stopWorkLoopTimer(interruptedBy, didCompleteRoot);interruptedBy = null;onYield(root);return;}// We completed the whole tree.const didCompleteRoot = true;stopWorkLoopTimer(interruptedBy, didCompleteRoot);const rootWorkInProgress = root.current.alternate;invariant(rootWorkInProgress !== null,'Finished root should have a work-in-progress. This error is likely ' +'caused by a bug in React. Please file an issue.',);// `nextRoot` points to the in-progress root. A non-null value indicates// that we're in the middle of an async render. Set it to null to indicate// there's no more work to be done in the current batch.nextRoot = null;interruptedBy = null;// 这里也是if (nextRenderDidError) {// There was an errorif (hasLowerPriorityWork(root, expirationTime)) {// There's lower priority work. If so, it may have the effect of fixing// the exception that was just thrown. Exit without committing. This is// similar to a suspend, but without a timeout because we're not waiting// for a promise to resolve. React will restart at the lower// priority level.markSuspendedPriorityLevel(root, expirationTime);const suspendedExpirationTime = expirationTime;const rootExpirationTime = root.expirationTime;onSuspend(root,rootWorkInProgress,suspendedExpirationTime,rootExpirationTime,-1, // Indicates no timeout);return;} else if (// There's no lower priority work, but we're rendering asynchronously.// Synchronsouly attempt to render the same level one more time. This is// similar to a suspend, but without a timeout because we're not waiting// for a promise to resolve.!root.didError &&!isExpired) {root.didError = true;const suspendedExpirationTime = (root.nextExpirationTimeToWorkOn = expirationTime);const rootExpirationTime = (root.expirationTime = Sync);onSuspend(root,rootWorkInProgress,suspendedExpirationTime,rootExpirationTime,-1, // Indicates no timeout);return;}}// 注意这里的错误if (!isExpired && nextLatestAbsoluteTimeoutMs !== -1) {// The tree was suspended.const suspendedExpirationTime = expirationTime;markSuspendedPriorityLevel(root, suspendedExpirationTime);// Find the earliest uncommitted expiration time in the tree, including// work that is suspended. The timeout threshold cannot be longer than// the overall expiration.const earliestExpirationTime = findEarliestOutstandingPriorityLevel(root,expirationTime,);const earliestExpirationTimeMs = expirationTimeToMs(earliestExpirationTime);if (earliestExpirationTimeMs < nextLatestAbsoluteTimeoutMs) {nextLatestAbsoluteTimeoutMs = earliestExpirationTimeMs;}// Subtract the current time from the absolute timeout to get the number// of milliseconds until the timeout. In other words, convert an absolute// timestamp to a relative time. This is the value that is passed// to `setTimeout`.const currentTimeMs = expirationTimeToMs(requestCurrentTime());let msUntilTimeout = nextLatestAbsoluteTimeoutMs - currentTimeMs;msUntilTimeout = msUntilTimeout < 0 ? 0 : msUntilTimeout;// TODO: Account for the Just Noticeable Differenceconst rootExpirationTime = root.expirationTime;onSuspend(root,rootWorkInProgress,suspendedExpirationTime,rootExpirationTime,msUntilTimeout,);return;}// Ready to commit.onComplete(root, rootWorkInProgress, expirationTime);
}
- renderRoot 代码会相对比较长,要把代码的区块进行一个区分
- 一些原版英文注释,和我添加的中文注释如上
现在来看下 workLoop 的源码
function workLoop(isYieldy) {if (!isYieldy) {// Flush work without yieldingwhile (nextUnitOfWork !== null) {nextUnitOfWork = performUnitOfWork(nextUnitOfWork);}} else {// Flush asynchronous work until the deadline runs out of time.while (nextUnitOfWork !== null && !shouldYield()) {nextUnitOfWork = performUnitOfWork(nextUnitOfWork);}}
}
- 它接收一个 isYieldy 作为参数
- 这个参数意味着是否可以被中断
- Sync的任务和已超时的异步任务都是不可中断的
- 如果是不可中断的,只要有
nextUnitOfWork
- 就会继续调用
performUnitOfWork
- 如果是可以中断的,就通过判断
!shouldYield()
- 来看当前时间片中是否还有足够的时间继续渲染下一个节点
再来看下 performUnitOfWork
function performUnitOfWork(workInProgress: Fiber): Fiber | null {// The current, flushed, state of this fiber is the alternate.// Ideally nothing should rely on this, but relying on it here// means that we don't need an additional field on the work in// progress.const current = workInProgress.alternate;// See if beginning this work spawns more work.startWorkTimer(workInProgress);if (__DEV__) {ReactCurrentFiber.setCurrentFiber(workInProgress);}if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) {stashedWorkInProgressProperties = assignFiberPropertiesInDEV(stashedWorkInProgressProperties,workInProgress,);}let next;if (enableProfilerTimer) {if (workInProgress.mode & ProfileMode) {startProfilerTimer(workInProgress);}next = beginWork(current, workInProgress, nextRenderExpirationTime);workInProgress.memoizedProps = workInProgress.pendingProps;if (workInProgress.mode & ProfileMode) {// Record the render duration assuming we didn't bailout (or error).stopProfilerTimerIfRunningAndRecordDelta(workInProgress, true);}} else {next = beginWork(current, workInProgress, nextRenderExpirationTime);workInProgress.memoizedProps = workInProgress.pendingProps;}if (__DEV__) {ReactCurrentFiber.resetCurrentFiber();if (isReplayingFailedUnitOfWork) {// Currently replaying a failed unit of work. This should be unreachable,// because the render phase is meant to be idempotent, and it should// have thrown again. Since it didn't, rethrow the original error, so// React's internal stack is not misaligned.rethrowOriginalError();}}if (__DEV__ && ReactFiberInstrumentation.debugTool) {ReactFiberInstrumentation.debugTool.onBeginWork(workInProgress);}if (next === null) {// If this doesn't spawn new work, complete the current work.next = completeUnitOfWork(workInProgress);}ReactCurrentOwner.current = null;return next;
}
- 它声明了一个 next 变量,next = beginWork(…), 这里涉及到对每个节点的更新
- 更新完一个节点之后,它会返回它的下一个节点
- 会更新 workInProgress.memoizedProps, 节点已经更新完了
- 最新的 props 已经变成目前正在用的 props
- 先跳过
- 跳过 DEV 的代码
- 如果 next === null 说明这个节点已经更新到子树的叶子节点了
- 这棵子树就可以结束了
- 结束就调用 completeUnitOfWork
- 它也会返回它的下一个节点
- 最后,return next
- 在 workLoop 函数中可看到,它会赋值给 nextUnitOfWork
// 参考其中一个 while while (nextUnitOfWork !== null) {nextUnitOfWork = performUnitOfWork(nextUnitOfWork); }
- 所以,真正到 nextUnitOfWork 为 null 的情况是它到了根节点,即 FiberRoot 节点
- 它的 return 是 null,这时就跳出了 while 循环了
- 在 workLoop 函数中可看到,它会赋值给 nextUnitOfWork
相关文章:

React16源码: React中的renderRoot的源码实现
renderRoot 1 )概述 renderRoot 是一个非常复杂的方法这个方法里处理很多各种各样的逻辑, 它主要的工作内容是什么?A. 它调用 workLoop 进行循环单元更新 遍历整个 Fiber Tree,把每一个组件或者 dom 节点对应的Fiber 节点拿出来单一的进行更…...

GitHub项目推荐-incubator
项目地址 Github地址:GitHub - apache/incubator-anser 官网:Apache Answer | Free Open-source Q&A Platform 项目简述 这是Apache的一个开源在线论坛,也可以部署成为一个自有的QA知识库。项目主要使用了Go和Typescript来开发&#…...
如何使用ActiveMQ
ActiveMQ是Apache的一款开源消息总线,主要用来做消息的分发。使用ActiveMQ,通常需要以下步骤: 一、启动ActiveMQ 首先需要下载ActiveMQ,然后进行启动。启动后,可以在控制台创建队列,初始用户名和密码通常…...
《Python 3 基础》- numpy的array,python的list、tuple的区别与联系再辨析
这里写自定义目录标题 一、基本认识二、list与传统数组(以C为例)的联系与区别三、1维list切片规则四、2维list类似于2维数组,但表达方式需适应五、list与元组的联系与区别1. tuple的创建方法类似于list,tuple用(&#…...

写点东西《最佳 Web 框架不存在 》
写点东西《🥇最佳 Web 框架不存在 🚫》 TLDR;您选择的 Web 应用程序框架并不重要。嗯,它很重要,但并不像其他人希望您相信的那样重要。 2024 年存在如此多的库和框架,而且最好的库和框架仍然备受争议&…...

游戏开发丨基于PyGlet的简易版Minecraft我的世界游戏
文章目录 写在前面我的世界PyGlet简介实验内容游戏按键程序设计引入文件 运行结果写在后面 写在前面 本期内容:基于PyGlet的简易版Minecraft我的世界游戏 实验环境: pycharmpyglet 项目下载地址:https://download.csdn.net/download/m0_6…...

在线的货币兑换平台源码下载
在线的货币兑换平台,可帮助全球各地的个人和企业将货币从一种货币兑换为另一种货币。该货币兑换平台是 Codecanyon 中最先进的脚本。 源码下载:https://download.csdn.net/download/m0_66047725/88728084...

LLMs之GLM-4:GLM-4的简介、安装和使用方法、案例应用之详细攻略
LLMs之GLM-4:GLM-4的简介、安装和使用方法、案例应用之详细攻略 导读:2024年01月16日,智谱AI在「智谱AI技术开放日(Zhipu DevDay)」推出新一代基座大模型GLM-4。GLM-4 的主要亮点和能力如下:>> 性能与GPT-4相近:多模态、长文…...

用Python“自动连发消息”
自动连发消息,基本上C和Python的思路都是不停的模拟“击键”操作,还有一种VB的脚本写法,反成每种语言都能写,更厉害的可以用java做出个GUI界面,先上代码。 一 代码 import pyautogui # 鼠标 import p…...

CSS3中多列布局详解
多列布局 概念:在CSS3之前,想要设计类似报纸那样的多列布局,有两种方式可以实现:一种是"浮动布局",另一种是“定位布局”。 这两种方式都有缺点:浮动布局比较灵活,但不容易控制&…...

Xmind 网页端登录及多端同步
好久没用 Xmind 了,前几天登录网页端突然发现没办法登录了,总是跳转到 Xmind AI 页面。本以为他们不再支持网页端了,后来看提示才知道只是迁移到了新的网址,由原来的 xmind.works 现在改成了的 xmind.ai。又花费好长时间才重新登录…...

Transformer从菜鸟到新手(七)
引言 上篇文章加速推理的KV缓存技术,本文介绍让我们可以得到更好的BLEU分数的解码技术——束搜索。 束搜索 我们之前生成翻译结果的时候,使用的是最简单的贪心搜索,即每次选择概率最大的,但是每次生成都选择概率最大的并不一定…...

上海AI实验室等开源,音频、音乐统一开发工具包Amphion
上海AI实验室、香港中文大学数据科学院、深圳大数据研究院联合开源了一个名为Amphion的音频、音乐和语音生成工具包。 Amphion可帮助开发人员研究文本生成音频、音乐等与音频相关的领域,可以在一个框架内完成,以解决生成模型黑箱、代码库分散、缺少评估…...
加快网络安全事件响应速度的6个步骤
现代安全工具不断提高保护组织网络和端点免受网络犯罪分子侵害的能力。但坏人偶尔还是会找到办法进来。 安全团队必须能够阻止威胁并尽快恢复正常运行。这就是为什么这些团队不仅必须拥有正确的工具,而且还要了解如何有效地应对事件。可以自定义事件响应模板等资源…...
Docker 镜像的详解及创建(Dockerfile详解)
目录 镜像加载的原理 联合文件系统(UnionFS) 镜像结构的分层 Dockerfile Dockerfile结构 dockerfile常用命令 Dockerfile 编写规范 docker创建镜像的方法 基于现有镜像创建 示例: 基于本地模版创建 示例 基于Dockerfile 创建 示…...
JDBC事务
1.事务 数据库事务是一组数据库操作,它们被视为一个单一的逻辑工作单元,要么全部成功执行,要么全部回滚(撤销)到事务开始前的状态。事务是确保数据库数据一致性、完整性和可靠性的关键机制之一。 简单来说࿰…...

协方差矩阵自适应调整的进化策略(CMA-ES)
关于CMA-ES,其中 CMA 为协方差矩阵自适应(Covariance Matrix Adaptation),而进化策略(Evolution strategies, ES)是一种无梯度随机优化算法。CMA-ES 是一种随机或随机化方法,用于非线性、非凸函数的实参数(…...

gitee完整使用教程,创建项目并上传
目录 一 什么是gitee 二 安装Git 三 登录gitee,生成密钥 四 配置SSH密钥 五 创建项目 六 克隆仓库到本地 七 关联本地工程到远程仓库 八 添加文件 九 异常处理 十 删除仓储 十一 git常用命令 一 什么是gitee gitee是开源中国推出的基于git的代码托管服务…...
如何使用ActiveMQ详细讲解
ActiveMQ 是一款流行的消息中间件,支持多种通信协议和消息模式,包括点对点、发布/订阅、事务处理等。下面是使用 ActiveMQ 的基本步骤: 1. 下载和安装 ActiveMQ: • 前往 ActiveMQ 的官方网站(http://activemq.apach…...

【python入门】day28:记录用户登录日志
演示 代码 #-*- coding:utf-8 -*- print(记录用户登录日志----------------------------) import time def show_info():print(输入提示数字,执行相应操作:0退出,1查看登录日志) def write_logininfo(username):#----------记录日志with open(log.txt,a,encodingutf-8)as file…...

测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...

工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...

HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...