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

React16源码: React中的renderRoot的错误处理的源码实现

renderRoot的错误处理


1 )概述

  • completeWork这个方法之后, 再次回到 renderRoot 里面
  • renderRoot 里面执行了 workLoop, 之后,对 workLoop 使用了try catch
  • 如果在里面有任何一个节点在更新的过程当中 throw Error 都会被catch到
  • catch到之后就是错误处理
    • 给报错节点增加 incomplete 副作用
      • incomplete 的副作用在 completeUnitOfWork 的时候,用来进行判断
      • 是要调用 completeWork,还是调用 unwindWork
    • 需要给父链上具有 error boundary 的节点增加副作用
      • 让它去收集错误以及进行一定的处理
    • 还需要创建错误相关的更新

2 )源码

定位到 packages/react-reconciler/src/ReactFiberScheduler.js#L1293

renderRoot 里面的 do while 循环中

do {try {workLoop(isYieldy);// 在catch里面得到了一个 thrownValue, 这是一个error} catch (thrownValue) {resetContextDependences();resetHooks();// Reset in case completion throws.// This is only used in DEV and when replaying is on.let mayReplay;if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) {mayReplay = mayReplayFailedUnitOfWork;mayReplayFailedUnitOfWork = true;}// 如果 nextUnitOfWork 等于 null,这是一个不属于正常流程里面的一个情况// 因为 nextUnitOfWork 是我们在更新一个节点之前,它是有值的更新// 更新节点之后,它会被赋成一个新的值// 一般来说它不应该是会存在 nextUnitOfWork 是 null 的一个情况// 即便 throw error 了,上一个 nextUnitOfWork 也没有主动去把它消除if (nextUnitOfWork === null) {// This is a fatal error.// 为 null 这种情况,被认为是一个致命的错误didFatal = true;// 调用 onUncaughtError,无法处理的错误被抛出了// 这个时候,react是会直接中断渲染染流程onUncaughtError(thrownValue);} else {// 非上述致命错误if (enableProfilerTimer && nextUnitOfWork.mode & ProfileMode) {// Record the time spent rendering before an error was thrown.// This avoids inaccurate Profiler durations in the case of a suspended render.stopProfilerTimerIfRunningAndRecordDelta(nextUnitOfWork, true);}if (__DEV__) {// Reset global debug state// We assume this is defined in DEV(resetCurrentlyProcessingQueue: any)();}if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) {if (mayReplay) {const failedUnitOfWork: Fiber = nextUnitOfWork;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;// 如果 returnFiber 等于 null, 说明这个错误是出现在更新 RootFiber 的过程当中// 那么 RootFiber 它是一个非常固定的节点,就是说它没有用户代码去进行一个参与的// 如果这个它出现了一个错误,也是一个致命的错误,是一个react源码级的一个错误,同上一样处理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);
  • 进入 onUncaughtError

    function onUncaughtError(error: mixed) {invariant(nextFlushedRoot !== null,'Should be working on a root. This error is likely caused by a bug in ' +'React. Please file an issue.',);// Unschedule this root so we don't work on it again until there's// another update.// 这时候直接把 nextFlushedRoot 设置成 NoWork,剩下的任务都不再执行了nextFlushedRoot.expirationTime = NoWork;// 处理全局变量if (!hasUnhandledError) {hasUnhandledError = true;unhandledError = error;}
    }
    
  • 进入 throwException 这个是常规处理错误的处理器

    function throwException(root: FiberRoot,returnFiber: Fiber,sourceFiber: Fiber,value: mixed,renderExpirationTime: ExpirationTime,
    ) {// 增加 Incomplete 这个 SideEffect// 这也是在 completeUnitOfWork 当中,去判断节点,是否有 Incomplete 的来源// 只有在这个节点,throw了一个异常之后,它才会被赋值 SideEffect// The source fiber did not complete.sourceFiber.effectTag |= Incomplete;// Its effect list is no longer valid.// 对 firstEffect 和 lastEffect 置 null// 因为它已经抛出一个异常了,子节点不会再进行渲染,不会有effect的一个链sourceFiber.firstEffect = sourceFiber.lastEffect = null;// 这种就匹配 Promise对象,或者 thenable 对象// 这个其实就对应 Suspense 相关的处理,通过 throw 一个 thenable 的对象// 可以让这个组件变成一个挂起的状态,等到这个 Promise 被 resolve之后,再次进入一个正常的渲染周期// 这部分都是跟 Suspense 相关的代码,先跳过if (value !== null &&typeof value === 'object' &&typeof value.then === 'function') {// This is a thenable.const thenable: Thenable = (value: any);// Find the earliest timeout threshold of all the placeholders in the// ancestor path. We could avoid this traversal by storing the thresholds on// the stack, but we choose not to because we only hit this path if we're// IO-bound (i.e. if something suspends). Whereas the stack is used even in// the non-IO- bound case.let workInProgress = returnFiber;let earliestTimeoutMs = -1;let startTimeMs = -1;do {if (workInProgress.tag === SuspenseComponent) {const current = workInProgress.alternate;if (current !== null) {const currentState: SuspenseState | null = current.memoizedState;if (currentState !== null && currentState.didTimeout) {// Reached a boundary that already timed out. Do not search// any further.const timedOutAt = currentState.timedOutAt;startTimeMs = expirationTimeToMs(timedOutAt);// Do not search any further.break;}}let timeoutPropMs = workInProgress.pendingProps.maxDuration;if (typeof timeoutPropMs === 'number') {if (timeoutPropMs <= 0) {earliestTimeoutMs = 0;} else if (earliestTimeoutMs === -1 ||timeoutPropMs < earliestTimeoutMs) {earliestTimeoutMs = timeoutPropMs;}}}workInProgress = workInProgress.return;} while (workInProgress !== null);// Schedule the nearest Suspense to re-render the timed out view.workInProgress = returnFiber;do {if (workInProgress.tag === SuspenseComponent &&shouldCaptureSuspense(workInProgress.alternate, workInProgress)) {// Found the nearest boundary.// If the boundary is not in concurrent mode, we should not suspend, and// likewise, when the promise resolves, we should ping synchronously.const pingTime =(workInProgress.mode & ConcurrentMode) === NoEffect? Sync: renderExpirationTime;// Attach a listener to the promise to "ping" the root and retry.let onResolveOrReject = retrySuspendedRoot.bind(null,root,workInProgress,sourceFiber,pingTime,);if (enableSchedulerTracing) {onResolveOrReject = Schedule_tracing_wrap(onResolveOrReject);}thenable.then(onResolveOrReject, onResolveOrReject);// If the boundary is outside of concurrent mode, we should *not*// suspend the commit. Pretend as if the suspended component rendered// null and keep rendering. In the commit phase, we'll schedule a// subsequent synchronous update to re-render the Suspense.//// Note: It doesn't matter whether the component that suspended was// inside a concurrent mode tree. If the Suspense is outside of it, we// should *not* suspend the commit.if ((workInProgress.mode & ConcurrentMode) === NoEffect) {workInProgress.effectTag |= CallbackEffect;// Unmount the source fiber's childrenconst nextChildren = null;reconcileChildren(sourceFiber.alternate,sourceFiber,nextChildren,renderExpirationTime,);sourceFiber.effectTag &= ~Incomplete;if (sourceFiber.tag === ClassComponent) {// We're going to commit this fiber even though it didn't complete.// But we shouldn't call any lifecycle methods or callbacks. Remove// all lifecycle effect tags.sourceFiber.effectTag &= ~LifecycleEffectMask;const current = sourceFiber.alternate;if (current === null) {// This is a new mount. Change the tag so it's not mistaken for a// completed component. For example, we should not call// componentWillUnmount if it is deleted.sourceFiber.tag = IncompleteClassComponent;}}// Exit without suspending.return;}// Confirmed that the boundary is in a concurrent mode tree. Continue// with the normal suspend path.let absoluteTimeoutMs;if (earliestTimeoutMs === -1) {// If no explicit threshold is given, default to an abitrarily large// value. The actual size doesn't matter because the threshold for the// whole tree will be clamped to the expiration time.absoluteTimeoutMs = maxSigned31BitInt;} else {if (startTimeMs === -1) {// This suspend happened outside of any already timed-out// placeholders. We don't know exactly when the update was// scheduled, but we can infer an approximate start time from the// expiration time. First, find the earliest uncommitted expiration// time in the tree, including work that is suspended. Then subtract// the offset used to compute an async update's expiration time.// This will cause high priority (interactive) work to expire// earlier than necessary, but we can account for this by adjusting// for the Just Noticeable Difference.const earliestExpirationTime = findEarliestOutstandingPriorityLevel(root,renderExpirationTime,);const earliestExpirationTimeMs = expirationTimeToMs(earliestExpirationTime,);startTimeMs = earliestExpirationTimeMs - LOW_PRIORITY_EXPIRATION;}absoluteTimeoutMs = startTimeMs + earliestTimeoutMs;}// Mark the earliest timeout in the suspended fiber's ancestor path.// After completing the root, we'll take the largest of all the// suspended fiber's timeouts and use it to compute a timeout for the// whole tree.renderDidSuspend(root, absoluteTimeoutMs, renderExpirationTime);workInProgress.effectTag |= ShouldCapture;workInProgress.expirationTime = renderExpirationTime;return;}// This boundary already captured during this render. Continue to the next// boundary.workInProgress = workInProgress.return;} while (workInProgress !== null);// No boundary was found. Fallthrough to error mode.value = new Error('An update was suspended, but no placeholder UI was provided.',);}// We didn't find a boundary that could handle this type of exception. Start// over and traverse parent path again, this time treating the exception// as an error.// renderDidError 方法 就是设置全局变量 nextRenderDidError 为 truerenderDidError();// 返回错误调用信息字符串value = createCapturedValue(value, sourceFiber);let workInProgress = returnFiber;// 根据tag匹配处理程序do {// 它其实就是往上去找它,要找到第一个可以处理错误的 class component // 来进行一个错误的update的一个创建,并且让它入栈// 等后期在commit的时候可以进行一个调用// 如果都没有,那么它会到 HostRoot 上面来进行处理错误// 因为 HostRoot 它相当于是一个内置的错误处理的方式// 也会创建对应的update,然后进行一个入队列,然后后续进行一个调用的过程// 这就是一个 throw exception,对于错误处理的一个情况switch (workInProgress.tag) {case HostRoot: {const errorInfo = value;workInProgress.effectTag |= ShouldCapture;workInProgress.expirationTime = renderExpirationTime;// 这个 update 类似于 setState 创建的对象const update = createRootErrorUpdate(workInProgress,errorInfo,renderExpirationTime,);enqueueCapturedUpdate(workInProgress, update);return;}// case ClassComponent:// Capture and retryconst errorInfo = value;const ctor = workInProgress.type;const instance = workInProgress.stateNode;// 它要先去判断一下,它现在没有 DidCapture 这个 SideEffect// 并且它是有 getDerivedStateFromError 这么一个方法// 或者它是有 componentDidCatch 生命周期方法if ((workInProgress.effectTag & DidCapture) === NoEffect &&(typeof ctor.getDerivedStateFromError === 'function' ||(instance !== null &&typeof instance.componentDidCatch === 'function' &&!isAlreadyFailedLegacyErrorBoundary(instance)))) {// 在这种情况下,我们就可以给它加上 ShouldCapture 这个 SideEffect// 并且呢设置它的 expirationTime 等于 renderExpirationTime// 因为我要去对这个组件, 在这个周期里面进行一个更新的过程// 然后他也要去创建一个update调用的是 createClassErrorUpdateworkInProgress.effectTag |= ShouldCapture;workInProgress.expirationTime = renderExpirationTime;// Schedule the error boundary to re-render using updated stateconst update = createClassErrorUpdate(workInProgress,errorInfo,renderExpirationTime,);enqueueCapturedUpdate(workInProgress, update);return;}break;default:break;}workInProgress = workInProgress.return;} while (workInProgress !== null);
    }
    
    • 进入 renderDidError
      // packages/react-reconciler/src/ReactFiberScheduler.js
      function renderDidError() {nextRenderDidError = true;
      }
      
    • 进入 createCapturedValue
      // packages/react-reconciler/src/ReactCapturedValue.js
      export function createCapturedValue<T>(value: T,source: Fiber,
      ): CapturedValue<T> {// If the value is an error, call this function immediately after it is thrown// so the stack is accurate.return {value,source,stack: getStackByFiberInDevAndProd(source),};
      }
      
      • 进入 getStackByFiberInDevAndProd
        function describeFiber(fiber: Fiber): string {switch (fiber.tag) {case IndeterminateComponent:case LazyComponent:case FunctionComponent:case ClassComponent:case HostComponent:case Mode:const owner = fiber._debugOwner;const source = fiber._debugSource;const name = getComponentName(fiber.type);let ownerName = null;if (owner) {ownerName = getComponentName(owner.type);}return describeComponentFrame(name, source, ownerName);default:return '';}
        }// 类似于js里面的error对象,它会有一个stack的信息
        // 就是哪个文件或者哪个方法调用的时候,它出现了错误,并且附上文件对应的代码的行数之类的信息
        export function getStackByFiberInDevAndProd(workInProgress: Fiber): string {let info = '';let node = workInProgress;// 形成一个错误调用信息的过程do {info += describeFiber(node);node = node.return;} while (node);return info;
        }
        
      • 进入 createRootErrorUpdate
        function createRootErrorUpdate(fiber: Fiber,errorInfo: CapturedValue<mixed>,expirationTime: ExpirationTime,
        ): Update<mixed> {const update = createUpdate(expirationTime);// Unmount the root by rendering null.update.tag = CaptureUpdate;// Caution: React DevTools currently depends on this property// being called "element".update.payload = {element: null};const error = errorInfo.value;update.callback = () => {// 打印 erroronUncaughtError(error);logError(fiber, errorInfo);};return update;
        }
        
      • 进入 enqueueCapturedUpdate
        // 没有则创建,有则克隆
        // 挂载 update
        export function enqueueCapturedUpdate<State>(workInProgress: Fiber,update: Update<State>,
        ) {// Captured updates go into a separate list, and only on the work-in-// progress queue.let workInProgressQueue = workInProgress.updateQueue;if (workInProgressQueue === null) {workInProgressQueue = workInProgress.updateQueue = createUpdateQueue(workInProgress.memoizedState,);} else {// TODO: I put this here rather than createWorkInProgress so that we don't// clone the queue unnecessarily. There's probably a better way to// structure this.workInProgressQueue = ensureWorkInProgressQueueIsAClone(workInProgress,workInProgressQueue,);}// Append the update to the end of the list.if (workInProgressQueue.lastCapturedUpdate === null) {// This is the first render phase updateworkInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update;} else {workInProgressQueue.lastCapturedUpdate.next = update;workInProgressQueue.lastCapturedUpdate = update;}
        }
        
      • 进入 createClassErrorUpdate
        function createClassErrorUpdate(fiber: Fiber,errorInfo: CapturedValue<mixed>,expirationTime: ExpirationTime,
        ): Update<mixed> {// 创建 updateconst update = createUpdate(expirationTime);// 标记 tagupdate.tag = CaptureUpdate;const getDerivedStateFromError = fiber.type.getDerivedStateFromError;// 存在 getDerivedStateFromError 则作为 payload 回调处理if (typeof getDerivedStateFromError === 'function') {const error = errorInfo.value;update.payload = () => {return getDerivedStateFromError(error);};}const inst = fiber.stateNode;if (inst !== null && typeof inst.componentDidCatch === 'function') {// 这个有组件错误被捕获之后,它会向上去找有能够处理捕获错误信息的这个class component 来处理// 如果都没有,它才会到 root 上面来进行一个处理// 它会根据像 getDerivedStateFromError 以及 componentDidCatch 这些生命周期方法来进行一个处理// 如果都没有这个指定,那么这个classcomponent 是没有一个错误处理的功能的// 如果有就会对应的进行这些操作来进行一个调用update.callback = function callback() {if (typeof getDerivedStateFromError !== 'function') {// To preserve the preexisting retry behavior of error boundaries,// we keep track of which ones already failed during this batch.// This gets reset before we yield back to the browser.// TODO: Warn in strict mode if getDerivedStateFromError is// not defined.markLegacyErrorBoundaryAsFailed(this);}const error = errorInfo.value;const stack = errorInfo.stack;// 输出 errorlogError(fiber, errorInfo);// 调用catch回调钩子 传入 stackthis.componentDidCatch(error, {componentStack: stack !== null ? stack : '',});if (__DEV__) {if (typeof getDerivedStateFromError !== 'function') {// If componentDidCatch is the only error boundary method defined,// then it needs to call setState to recover from errors.// If no state update is scheduled then the boundary will swallow the error.warningWithoutStack(fiber.expirationTime === Sync,'%s: Error boundaries should implement getDerivedStateFromError(). ' +'In that method, return a state update to display an error message or fallback UI.',getComponentName(fiber.type) || 'Unknown',);}}};}return update;
        }
        
  • 经过以上的处理,在调用了所有 exception 之后,最后 立马调用了 completeUnitOfWork

  • 这就说明这个节点报错了,这个节点已经完成了,它不会再继续去渲染它的子节点了

  • 因为这个节点它已经出错了,再渲染它的子节点是没有任何意义

  • 所以在这里面,如果有一个节点,出错了,就会立马对它执行 completeUnitOfWork

  • 它走的就是 unwindWork 的流程了, 这个后续来看

相关文章:

React16源码: React中的renderRoot的错误处理的源码实现

renderRoot的错误处理 1 &#xff09;概述 在 completeWork这个方法之后, 再次回到 renderRoot 里面在 renderRoot 里面执行了 workLoop, 之后&#xff0c;对 workLoop 使用了try catch如果在里面有任何一个节点在更新的过程当中 throw Error 都会被catch到catch到之后就是错误…...

强化学习:MuJoCo机器人强化学习仿真入门(1)

声明&#xff1a;我们跳过mujoco环境的搭建&#xff0c;搭建环境不难&#xff0c;可自行百度 下面开始进入正题&#xff08;需要有一定的python基础与xml基础&#xff09;&#xff1a; 下面进入到建立机器人模型的部分&#xff1a; 需要先介绍URDF模型文件和导出MJCF格式 介绍完…...

8.Gateway服务网关

3.Gateway服务网关 Spring Cloud Gateway 是 Spring Cloud 的一个全新项目&#xff0c;该项目是基于 Spring 5.0&#xff0c;Spring Boot 2.0 和 Project Reactor 等响应式编程和事件流技术开发的网关&#xff0c;它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式…...

JVM篇----第四篇

系列文章目录 文章目录 系列文章目录前言一、虚拟机栈(线程私有)二、本地方法区(线程私有)三、你能保证 GC 执行吗?四、怎么获取 Java 程序使用的内存?堆使用的百分比?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到…...

WPF引用halcon的HSmartWindowControlWPF控件一加上Name属性就,无缘无故运行后报错

报错内容&#xff1a; 严重性 代码 说明 项目 文件 行 禁止显示状态 错误 MC1000 未知的生成错误“Could not find assembly System.Drawing.Common, Version0.0.0.0, Cultureneutral, PublicKeyTokencc7b13ffcd2ddd51. Either explicitly load this assembly using a method …...

Vue3组件库开发 之Button(2) 未完待续

Vue3组件库开发 之Button(1) 中新建项目&#xff0c;但未安装成功ESLINT 安装ESLINT npm install eslint vite-plugin-eslint --save-dev 安装eslint后&#xff0c;组件文件出现错误提示 添加第三方macros &#xff0c;虽然不是官网但很多开发者都是vue3开发人员 安装macros…...

k8s节点RouteCreated为false

出现该情况后&#xff0c;一般是初始化节点失败。因此&#xff0c;需要把节点从集群中移除&#xff0c;再加入到集群中&#xff0c;即可解决。 通常出现这个状况后&#xff0c;该节点上是没有被分配pod ip的&#xff0c;可以通过命令查看&#xff1a; # 发现没有PodCIDR、PodC…...

Kafka(二)原理详解

一 、kafka核心总控制器&#xff08;Controller&#xff09; 在Kafka集群中会有一个或者多个broker&#xff0c;其中有一个broker会被选举为控制器&#xff08;Kafka Controller&#xff09;&#xff0c;它负责管理整个集群中所有分区和副本的状态。 作用&#xff1a;leader副…...

Flutter 屏幕适配之相对尺寸适配

在Android中我们可以通过脚本来动态生成适配于各个厂商的屏幕的相对尺寸。 那么在Flutter中我们如何通过相同的思路来实现同样的效果呢&#xff1f;我们知道&#xff0c;Android的每个厂商的屏幕大小存在非常大区别。有些长&#xff0c;有的短&#xff0c;有的粗&#xff0c;有…...

在线预约小程序源码系统:适合任何行业的在线预约,快捷方便,省时省心 带完整的搭建教程

互联网技术的发展&#xff0c;人们对便捷服务的需求越来越高。特别是在线预约服务&#xff0c;无论是在医疗、美容、餐饮还是其他行业中&#xff0c;用户都希望能够通过简单的方式预约到所需的服务。然而&#xff0c;传统的预约方式往往效率低下&#xff0c;不能满足用户的快速…...

AI部署开发指南:用vs2019编译OnnxRuntime-v1.16.2

前言 要详细了解一个系统的部署&#xff0c;对其源码进行调试可能是最好的办法。 Pytorch的部署几经改版&#xff0c;最大的特点依然是不稳定&#xff0c;或者使用libtorch这种稳定但优化力度不够的部署方案。 而稳定且通用的方案&#xff0c;目前仍然是export to onnx的办法…...

【强化学习】QAC、A2C、A3C学习笔记

强化学习算法&#xff1a;QAC vs A2C vs A3C 引言 经典的REINFORCE算法为我们提供了一种直接优化策略的方式&#xff0c;它通过梯度上升方法来寻找最优策略。然而&#xff0c;REINFORCE算法也有其局限性&#xff0c;采样效率低、高方差、收敛性差、难以处理高维离散空间。 为…...

android usb2.0 协议基础(2)

2.4 USB逻辑部件 USB 逻辑部件 设备---》 接口 &#xff08;一个或多个&#xff09;&#xff1a;用于描述特定功能&#xff0c;包含多个端点----》端点&#xff08;一个或多个&#xff09;&#xff1a; 传输的最终对象端点号&#xff0c;传输类型传输方向&#xff0c;最大的数据…...

C语言快速排序(非递归)图文详解

前言&#xff1a; 上一期分析了快速排序的三种写法&#xff0c;这三种写法有一个相同点&#xff0c;都是采用递归形式来实现的&#xff0c;那么有没有非递归的方法实现呢&#xff1f;答案是当然有&#xff0c;用非递归的方法实现快速排序&#xff0c;其实可以借助数据结构中的栈…...

Java面试题136-150

36、用JDBC如何调用存储过程 代码如下&#xff1a; package com.huawei.interview.lym; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Types; public class JdbcTest…...

使用trace工具分析Mysql如何选择索引

背景说明 工作中,可能会遇到执行一个SQL,明明有索引,但是采用explain分析后发现执行结果并未走索引。甚至还有部分SQL语句相同就只是查询条件不一样也会出现有的走索引,有的不走索引情况。比如: 我的示例环境有个employees表,并有个idx_name_age_position的联合索引…...

微信小程序(十二)在线图标与字体的获取与引入

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.从IconFont获取图标与文字的样式链接 2.将在线图标配置进页面中&#xff08;源码&#xff09; 3.将字体配置进页面文字中&#xff08;源码&#xff09; 4.css样式的多文件导入 获取链接 1.获取图标链接 登入…...

分类预测 | Matlab实现LSTM-Attention-Adaboost基于长短期记忆网络融合注意力机制的Adaboost数据分类预测/故障识别

分类预测 | Matlab实现LSTM-Attention-Adaboost基于长短期记忆网络融合注意力机制的Adaboost数据分类预测/故障识别 目录 分类预测 | Matlab实现LSTM-Attention-Adaboost基于长短期记忆网络融合注意力机制的Adaboost数据分类预测/故障识别分类效果基本描述程序设计参考资料 分类…...

java web mvc-04-Apache Wicket

拓展阅读 Spring Web MVC-00-重学 mvc mvc-01-Model-View-Controller 概览 web mvc-03-JFinal web mvc-04-Apache Wicket web mvc-05-JSF JavaServer Faces web mvc-06-play framework intro web mvc-07-Vaadin web mvc-08-Grails 开源 The jdbc pool for java.(java …...

暴力破解常见的服务器

目录 使用 pydictor 生成自己的字典工具liunx下载使用常用的参数说明插件型字典 (可自己根据 API 文档开发) 使用 hydra 工具在线破解系统用户密码使用 hydra 破解 windows 7 远程桌面密码使用 hydra 工具破解 ssh 服务 root 用户密码 使用 Medusa 工具在线破解medusa参数说明M…...

腾讯云秒杀活动是什么?2026年最新参与指南(附抢购技巧)

腾讯云秒杀活动是什么&#xff1f;怎么参与&#xff1f;本文将详细解析腾讯云秒杀活动规则、参与入口、抢购技巧及备选方案&#xff0c;助力大家低成本开启云端之旅&#xff01; 一、活动介绍 腾讯云秒杀活动是腾讯云官方推出的限量限时抢购活动&#xff0c;主打高性价比的轻量…...

三量子比特控制旋转门:挑战与创新协议设计

1. 三量子比特控制旋转门的核心挑战在量子计算领域&#xff0c;多量子比特门是实现复杂量子算法的关键构建模块。其中&#xff0c;三量子比特控制旋转门(C2Ry)作为一种基本的多量子比特操作&#xff0c;能够根据两个控制量子比特的状态对目标量子比特执行条件旋转&#xff0c;在…...

基于CCS811与CircuitPython的可穿戴呼吸监测面具制作全解析

1. 项目概述与核心价值 几年前&#xff0c;当我第一次接触到可穿戴健康设备时&#xff0c;就被其潜力深深吸引。但市面上的产品要么是封闭的“黑盒”&#xff0c;数据不透明&#xff1b;要么价格高昂&#xff0c;难以进行个性化定制。我一直想&#xff0c;能不能自己动手做一个…...

为什么你的Midjourney胶片图总像数码后期?——从光子散射模型到显影时间算法的底层差异解析

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;胶片质感的视觉直觉与认知偏差 胶片质感并非单纯的技术残留&#xff0c;而是一种经由人类视觉系统长期训练形成的感知锚点——它将颗粒噪点、色偏渐变、边缘晕影等非理想光学特征&#xff0c;编码为“真…...

Spring Data Redis入门指南:5分钟快速搭建你的第一个Redis应用

Spring Data Redis入门指南&#xff1a;5分钟快速搭建你的第一个Redis应用 【免费下载链接】spring-data-redis Provides support to increase developer productivity in Java when using Redis, a key-value store. Uses familiar Spring concepts such as a template classe…...

5个PoE Overlay技巧:从新手到交易专家的快速升级指南

5个PoE Overlay技巧&#xff1a;从新手到交易专家的快速升级指南 【免费下载链接】PoE-Overlay An Overlay for Path of Exile. Built with Overwolf and Angular. 项目地址: https://gitcode.com/gh_mirrors/po/PoE-Overlay 你是否曾在《流放之路》中为装备价值判断而困…...

为什么你的ElevenLabs免费额度突然归零?4个未公开的触发条件,第2条99%人中招!

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;ElevenLabs免费额度突然归零的真相揭秘 近期大量开发者反馈 ElevenLabs 的免费 API 额度&#xff08;10,000 characters/month&#xff09;在未达用量上限时被强制重置为 0&#xff0c;且控制台不显示…...

从Crustocean/conch看轻量级工作流编排:DAG原理与Python实现

1. 项目概述&#xff1a;从“Crustocean/conch”看现代数据管道编排的演进最近在梳理团队的数据处理流程时&#xff0c;我又一次被那些错综复杂的脚本、定时任务和手动依赖检查搞得焦头烂额。这让我想起了几年前第一次接触“Crustocean/conch”这个项目时的情景。当时&#xff…...

手把手教你模拟登录淘宝并爬取订单数据:从Cookie维护到反爬突破的完全指南

目录 一、技术选型:为什么最终选择了Playwright? 1.1 那些年被抛弃的方案 1.2 Playwright的优势 1.3 完整的依赖清单 二、登录流程的完整实现 2.1 两种登录方案的权衡 2.2 扫码登录的完整代码 2.3 Cookie持久化机制详解 三、订单列表爬取的两种思路 3.1 方式一:页…...

JetBrains IDE试用期重置完整指南:快速恢复30天免费使用权限

JetBrains IDE试用期重置完整指南&#xff1a;快速恢复30天免费使用权限 【免费下载链接】ide-eval-resetter 项目地址: https://gitcode.com/gh_mirrors/id/ide-eval-resetter 你是否正在使用JetBrains系列IDE进行开发&#xff0c;却面临试用期到期的问题&#xff1f;…...