React16源码: React中的updateClassComponent的源码实现
ClassComponent 的更新
1 ) 概述
- 在 react 中 class component,是一个非常重要的角色
- 它承担了 react 中 更新整个应用的API
setState
forceUpdate
- 在react当中,只有更新了state之后,整个应用才会重新进行渲染
- 在 class component 中, 它的逻辑相对复杂
2 )源码
在 packages/react-reconciler/src/ReactFiberBeginWork.js
// 这个方法就是更新 ClassComponent 组件的一个过程
function updateClassComponent(current: Fiber | null,workInProgress: Fiber,Component: any,nextProps,renderExpirationTime: ExpirationTime,
) {// Push context providers early to prevent context stack mismatches.// During mounting we don't know the child context yet as the instance doesn't exist.// We will invalidate the child context in finishClassComponent() right after rendering.// 先跳过 context 相关的逻辑let hasContext;if (isLegacyContextProvider(Component)) {hasContext = true;pushLegacyContextProvider(workInProgress);} else {hasContext = false;}prepareToReadContext(workInProgress, renderExpirationTime);// instance 就是我们 class component,通过new这个class获取的一个对象const instance = workInProgress.stateNode;// 在这里面,它声明了一个 shouldUpdate 的一个属性let shouldUpdate; // 先判断instance是否存在, 比如说我们第一次通过 ReactDOM.render 进行渲染的过程当中// 在从上往下第一次渲染的过程当中,第一次更新到 class component 的时候// 它的instance肯定是不存在的,因为它还没有被更新过,所以它的节点肯定是没有被创建的if (instance === null) {// 接下去, 判断一下current是否等于null// current等于null的情况是代表在进入第一次渲染,因为current它还不存在// 如果current不等于null, 代表我们至少已经经历过一次渲染了// 这时候 instance 不存在,而 current 存在,说明第一次渲染的时候没有创建这个instance// 同样说明这个组件是被 suspended 的,一个组件处于suspended的状态// 在这里react认为它相当于是第一次被渲染, 在初次渲染的时候,只是抛出了一个promise// 并没有真正的渲染出它的子节点, 抛出了一个promise之后,接下去的渲染就结束了if (current !== null) {// An class component without an instance only mounts if it suspended// inside a non- concurrent tree, in an inconsistent state. We want to// tree it like a new mount, even though an empty version of it already// committed. Disconnect the alternate pointers.current.alternate = null;workInProgress.alternate = null;// Since this is conceptually a new fiber, schedule a Placement effectworkInProgress.effectTag |= Placement;}// In the initial pass we might need to construct the instance.// 对于没有instance的一个情况,需要去创建 class instanceconstructClassInstance(workInProgress,Component,nextProps,renderExpirationTime,);// 并且要mount这个 class instancemountClassInstance(workInProgress,Component,nextProps,renderExpirationTime,);// 在第一次渲染的时候,会执行上述两个方法,并且 shouldUpdate = true;shouldUpdate = true;} else if (current === null) {// In a resume, we'll already have an instance we can reuse.// 在 有instance 和 没有 current 的情况下,这种是之前被中断的// 在执行 class component 的 render 方法的时候 报错,但 instance 已被创建// 代表着可以复用 instanceshouldUpdate = resumeMountClassInstance(workInProgress,Component,nextProps,renderExpirationTime,);} else {// 对于又有 current 又有 instance的情况,说明组件已经被重新渲染了// 这个 updateClassInstance 方法和 上述 resumeMountClassInstance 类似// 最大的区别是 内部判断 comonentDidUpdate shouldUpdate = updateClassInstance(current,workInProgress,Component,nextProps,renderExpirationTime,);}// 这里最终调用 finishClassComponentreturn finishClassComponent(current,workInProgress,Component,shouldUpdate,hasContext,renderExpirationTime,);
}
-
进入
constructClassInstance
function constructClassInstance(workInProgress: Fiber,ctor: any,props: any,renderExpirationTime: ExpirationTime, ): any {// 先跳过 context 相关let isLegacyContextConsumer = false;let unmaskedContext = emptyContextObject;let context = null;const contextType = ctor.contextType;// if (typeof contextType === 'object' && contextType !== null) {// 跳过 DEVif (__DEV__) {if (contextType.$$typeof !== REACT_CONTEXT_TYPE &&!didWarnAboutInvalidateContextType.has(ctor)) {didWarnAboutInvalidateContextType.add(ctor);warningWithoutStack(false,'%s defines an invalid contextType. ' +'contextType should point to the Context object returned by React.createContext(). ' +'Did you accidentally pass the Context.Provider instead?',getComponentName(ctor) || 'Component',);}}context = readContext((contextType: any));} else {unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);const contextTypes = ctor.contextTypes;isLegacyContextConsumer =contextTypes !== null && contextTypes !== undefined;context = isLegacyContextConsumer? getMaskedContext(workInProgress, unmaskedContext): emptyContextObject;}// Instantiate twice to help detect side-effects.if (__DEV__) {if (debugRenderPhaseSideEffects ||(debugRenderPhaseSideEffectsForStrictMode &&workInProgress.mode & StrictMode)) {new ctor(props, context); // eslint-disable-line no-new}}// ctor 是 construct 的一个缩写 这个 ctor 就是在 ReactElement当中// 存在的那个type,也就是 class component 定义的那个class// 传入 props和context,对应于 ReactBaseClasses.js 里面,Component 函数 接收的这两个参数// 第三个参数 updater 后面在 adoptClassInstance 里面设置const instance = new ctor(props, context);// 获取 stateconst state = (workInProgress.memoizedState =instance.state !== null && instance.state !== undefined? instance.state: null);adoptClassInstance(workInProgress, instance);if (__DEV__) {if (typeof ctor.getDerivedStateFromProps === 'function' && state === null) {const componentName = getComponentName(ctor) || 'Component';if (!didWarnAboutUninitializedState.has(componentName)) {didWarnAboutUninitializedState.add(componentName);warningWithoutStack(false,'`%s` uses `getDerivedStateFromProps` but its initial state is ' +'%s. This is not recommended. Instead, define the initial state by ' +'assigning an object to `this.state` in the constructor of `%s`. ' +'This ensures that `getDerivedStateFromProps` arguments have a consistent shape.',componentName,instance.state === null ? 'null' : 'undefined',componentName,);}}// If new component APIs are defined, "unsafe" lifecycles won't be called.// Warn about these lifecycles if they are present.// Don't warn about react-lifecycles-compat polyfilled methods though.if (typeof ctor.getDerivedStateFromProps === 'function' ||typeof instance.getSnapshotBeforeUpdate === 'function') {let foundWillMountName = null;let foundWillReceivePropsName = null;let foundWillUpdateName = null;if (typeof instance.componentWillMount === 'function' &&instance.componentWillMount.__suppressDeprecationWarning !== true) {foundWillMountName = 'componentWillMount';} else if (typeof instance.UNSAFE_componentWillMount === 'function') {foundWillMountName = 'UNSAFE_componentWillMount';}if (typeof instance.componentWillReceiveProps === 'function' &&instance.componentWillReceiveProps.__suppressDeprecationWarning !== true) {foundWillReceivePropsName = 'componentWillReceiveProps';} else if (typeof instance.UNSAFE_componentWillReceiveProps === 'function') {foundWillReceivePropsName = 'UNSAFE_componentWillReceiveProps';}if (typeof instance.componentWillUpdate === 'function' &&instance.componentWillUpdate.__suppressDeprecationWarning !== true) {foundWillUpdateName = 'componentWillUpdate';} else if (typeof instance.UNSAFE_componentWillUpdate === 'function') {foundWillUpdateName = 'UNSAFE_componentWillUpdate';}if (foundWillMountName !== null ||foundWillReceivePropsName !== null ||foundWillUpdateName !== null) {const componentName = getComponentName(ctor) || 'Component';const newApiName =typeof ctor.getDerivedStateFromProps === 'function'? 'getDerivedStateFromProps()': 'getSnapshotBeforeUpdate()';if (!didWarnAboutLegacyLifecyclesAndDerivedState.has(componentName)) {didWarnAboutLegacyLifecyclesAndDerivedState.add(componentName);warningWithoutStack(false,'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +'%s uses %s but also contains the following legacy lifecycles:%s%s%s\n\n' +'The above lifecycles should be removed. Learn more about this warning here:\n' +'https://fb.me/react-async-component-lifecycle-hooks',componentName,newApiName,foundWillMountName !== null ? `\n ${foundWillMountName}` : '',foundWillReceivePropsName !== null? `\n ${foundWillReceivePropsName}`: '',foundWillUpdateName !== null ? `\n ${foundWillUpdateName}` : '',);}}}}// Cache unmasked context so we can avoid recreating masked context unless necessary.// ReactFiberContext usually updates this cache but can't for newly-created instances.if (isLegacyContextConsumer) {cacheContext(workInProgress, unmaskedContext, context);}return instance; }
- 进入
adoptClassInstance
function adoptClassInstance(workInProgress: Fiber, instance: any): void {instance.updater = classComponentUpdater; // 挂载 update 方法workInProgress.stateNode = instance; // instance 挂载到 stateNode 以供下次进来时使用,下次进来就会存在了// The instance needs access to the fiber so that it can schedule updatesReactInstanceMap.set(instance, workInProgress);if (__DEV__) {instance._reactInternalInstance = fakeInternalInstance;} }
- 进入
ReactInstanceMap
这个就是对 instance 上_reactInternalFiber
属性的设置export function remove(key) {key._reactInternalFiber = undefined; }export function get(key) {return key._reactInternalFiber; }export function has(key) {return key._reactInternalFiber !== undefined; }export function set(key, value) {key._reactInternalFiber = value; }
- 这也意味着,通过
this._reactInternalFiber
就可以拿到当前 fiber 对象
- 这也意味着,通过
- 进入
-
进入
mountClassInstance
// Invokes the mount life-cycles on a previously never rendered instance. function mountClassInstance(workInProgress: Fiber,ctor: any,newProps: any,renderExpirationTime: ExpirationTime, ): void {if (__DEV__) {checkClassInstance(workInProgress, ctor, newProps);}const instance = workInProgress.stateNode;instance.props = newProps;instance.state = workInProgress.memoizedState;instance.refs = emptyRefsObject;const contextType = ctor.contextType;if (typeof contextType === 'object' && contextType !== null) {instance.context = readContext(contextType);} else {const unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);instance.context = getMaskedContext(workInProgress, unmaskedContext);}if (__DEV__) {if (instance.state === newProps) {const componentName = getComponentName(ctor) || 'Component';if (!didWarnAboutDirectlyAssigningPropsToState.has(componentName)) {didWarnAboutDirectlyAssigningPropsToState.add(componentName);warningWithoutStack(false,'%s: It is not recommended to assign props directly to state ' +"because updates to props won't be reflected in state. " +'In most cases, it is better to use props directly.',componentName,);}}if (workInProgress.mode & StrictMode) {ReactStrictModeWarnings.recordUnsafeLifecycleWarnings(workInProgress,instance,);ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress,instance,);}if (warnAboutDeprecatedLifecycles) {ReactStrictModeWarnings.recordDeprecationWarnings(workInProgress,instance,);}}// 获取 updateQueue,初次渲染这个 updateQueue 是空的// 对于有 setState 的情况,它的 updateQueen 里面可能有多个update// 这个时候, 需要调用这个 updateQueen 来去得到一个新的statelet updateQueue = workInProgress.updateQueue;if (updateQueue !== null) {// 这里 计算出新的state 并赋值给 workInProgress.memoizedStateprocessUpdateQueue(workInProgress,updateQueue,newProps,instance,renderExpirationTime,);// 同时更新 instance.stateinstance.state = workInProgress.memoizedState;}// 判断是否有这个生命周期方法const getDerivedStateFromProps = ctor.getDerivedStateFromProps;if (typeof getDerivedStateFromProps === 'function') {// 如果存在该生命周期方法,则计算新的state// 这个生命周期会在组件更新的过程中被调用applyDerivedStateFromProps(workInProgress,ctor,getDerivedStateFromProps,newProps,);instance.state = workInProgress.memoizedState;}// In order to support react-lifecycles-compat polyfilled components,// Unsafe lifecycles should not be invoked for components using the new APIs.// 判断是否有 componentWillMount 生命周期方法// 在这个生命周期方法中,会执行 setState 方法if (typeof ctor.getDerivedStateFromProps !== 'function' &&typeof instance.getSnapshotBeforeUpdate !== 'function' &&(typeof instance.UNSAFE_componentWillMount === 'function' ||typeof instance.componentWillMount === 'function')) {// callComponentWillMount(workInProgress, instance);// If we had additional state updates during this life-cycle, let's// process them now.// 执行了 这个生命周期方法,就需要重新执行 updateQueue// 如果在这时执行了 setState, 立马被反映到组件上面updateQueue = workInProgress.updateQueue;if (updateQueue !== null) {processUpdateQueue(workInProgress,updateQueue,newProps,instance,renderExpirationTime,);instance.state = workInProgress.memoizedState;}}if (typeof instance.componentDidMount === 'function') {workInProgress.effectTag |= Update;} }
- 进入
processUpdateQueue
export function processUpdateQueue<State>(workInProgress: Fiber,queue: UpdateQueue<State>,props: any,instance: any,renderExpirationTime: ExpirationTime, ): void {hasForceUpdate = false;// 克隆 updateQueuequeue = ensureWorkInProgressQueueIsAClone(workInProgress, queue);if (__DEV__) {currentlyProcessingQueue = queue;}// These values may change as we process the queue.let newBaseState = queue.baseState;let newFirstUpdate = null;let newExpirationTime = NoWork;// Iterate through the list of updates to compute the result.let update = queue.firstUpdate; let resultState = newBaseState;while (update !== null) {const updateExpirationTime = update.expirationTime;if (updateExpirationTime < renderExpirationTime) {// This update does not have sufficient priority. Skip it.if (newFirstUpdate === null) {// This is the first skipped update. It will be the first update in// the new list.newFirstUpdate = update;// Since this is the first update that was skipped, the current result// is the new base state.newBaseState = resultState;}// Since this update will remain in the list, update the remaining// expiration time.if (newExpirationTime < updateExpirationTime) {newExpirationTime = updateExpirationTime;}} else {// This update does have sufficient priority. Process it and compute// a new result.resultState = getStateFromUpdate(workInProgress,queue,update,resultState,props,instance,);const callback = update.callback;// 判断是否有 callbackif (callback !== null) {workInProgress.effectTag |= Callback; // 加上 Callback 这块// Set this to null, in case it was mutated during an aborted render.update.nextEffect = null; // 防止在中断的渲染中被修改if (queue.lastEffect === null) {queue.firstEffect = queue.lastEffect = update; // 链表操作} else {queue.lastEffect.nextEffect = update;queue.lastEffect = update;}}}// Continue to the next update.update = update.next;}// Separately, iterate though the list of captured updates.let newFirstCapturedUpdate = null;update = queue.firstCapturedUpdate;while (update !== null) {const updateExpirationTime = update.expirationTime;if (updateExpirationTime < renderExpirationTime) {// This update does not have sufficient priority. Skip it.if (newFirstCapturedUpdate === null) {// This is the first skipped captured update. It will be the first// update in the new list.newFirstCapturedUpdate = update;// If this is the first update that was skipped, the current result is// the new base state.if (newFirstUpdate === null) {newBaseState = resultState;}}// Since this update will remain in the list, update the remaining// expiration time.if (newExpirationTime < updateExpirationTime) {newExpirationTime = updateExpirationTime;}} else {// This update does have sufficient priority. Process it and compute// a new result.resultState = getStateFromUpdate(workInProgress,queue,update,resultState,props,instance,);const callback = update.callback;if (callback !== null) {workInProgress.effectTag |= Callback;// Set this to null, in case it was mutated during an aborted render.update.nextEffect = null;if (queue.lastCapturedEffect === null) {queue.firstCapturedEffect = queue.lastCapturedEffect = update;} else {queue.lastCapturedEffect.nextEffect = update;queue.lastCapturedEffect = update;}}}update = update.next;}if (newFirstUpdate === null) {queue.lastUpdate = null;}if (newFirstCapturedUpdate === null) {queue.lastCapturedUpdate = null;} else {workInProgress.effectTag |= Callback;}if (newFirstUpdate === null && newFirstCapturedUpdate === null) {// We processed every update, without skipping. That means the new base// state is the same as the result state.newBaseState = resultState;}queue.baseState = newBaseState;queue.firstUpdate = newFirstUpdate;queue.firstCapturedUpdate = newFirstCapturedUpdate;// Set the remaining expiration time to be whatever is remaining in the queue.// This should be fine because the only two other things that contribute to// expiration time are props and context. We're already in the middle of the// begin phase by the time we start processing the queue, so we've already// dealt with the props. Context in components that specify// shouldComponentUpdate is tricky; but we'll have to account for// that regardless.workInProgress.expirationTime = newExpirationTime;workInProgress.memoizedState = resultState;if (__DEV__) {currentlyProcessingQueue = null;} }
- 进入
ensureWorkInProgressQueueIsAClone
function ensureWorkInProgressQueueIsAClone<State>(workInProgress: Fiber,queue: UpdateQueue<State>, ): UpdateQueue<State> {const current = workInProgress.alternate;if (current !== null) {// If the work-in-progress queue is equal to the current queue,// we need to clone it first.if (queue === current.updateQueue) {// 要保证 workInProgress.updateQueue 是一个克隆的queue, 而非直接进行修改queue = workInProgress.updateQueue = cloneUpdateQueue(queue); // 拷贝 queue}}return queue; }
- 进入
- 进入
getStateFromUpdate
function getStateFromUpdate<State>(workInProgress: Fiber,queue: UpdateQueue<State>,update: Update<State>,prevState: State,nextProps: any,instance: any, ): any {switch (update.tag) {case ReplaceState: {const payload = update.payload;if (typeof payload === 'function') {// Updater functionif (__DEV__) {if (debugRenderPhaseSideEffects ||(debugRenderPhaseSideEffectsForStrictMode &&workInProgress.mode & StrictMode)) {payload.call(instance, prevState, nextProps);}}return payload.call(instance, prevState, nextProps);}// State objectreturn payload;}// 这里 a & ~b 表示: a & 除了b之外的所有属性case CaptureUpdate: {workInProgress.effectTag =(workInProgress.effectTag & ~ShouldCapture) | DidCapture; // 这里最终剩下的 只有 DidCapture}// Intentional fallthroughcase UpdateState: {const payload = update.payload;let partialState;if (typeof payload === 'function') {// Updater functionif (__DEV__) {if (debugRenderPhaseSideEffects ||(debugRenderPhaseSideEffectsForStrictMode &&workInProgress.mode & StrictMode)) {payload.call(instance, prevState, nextProps);}}// 如果是 function 则调用 payload 传入之前的参数 计算出 statepartialState = payload.call(instance, prevState, nextProps);} else {// Partial state objectpartialState = payload;}// 处理特殊情况if (partialState === null || partialState === undefined) {// Null and undefined are treated as no-ops.return prevState;}// Merge the partial state and the previous state.// 合并return Object.assign({}, prevState, partialState);}case ForceUpdate: {hasForceUpdate = true;return prevState;}}return prevState; }
- 进入
-
进入
finishClassComponent
function finishClassComponent(current: Fiber | null,workInProgress: Fiber,Component: any,shouldUpdate: boolean,hasContext: boolean,renderExpirationTime: ExpirationTime, ) {// Refs should update even if shouldComponentUpdate returns false// 这个先跳过markRef(current, workInProgress);// 判断 workInProgress.effectTag 上是否有 DidCaptureconst didCaptureError = (workInProgress.effectTag & DidCapture) !== NoEffect;// 在没有更新也没有错误捕获的情况下if (!shouldUpdate && !didCaptureError) {// Context providers should defer to sCU for renderingif (hasContext) {invalidateContextProvider(workInProgress, Component, false);}// 跳过更新return bailoutOnAlreadyFinishedWork(current,workInProgress,renderExpirationTime,);}const instance = workInProgress.stateNode;// RerenderReactCurrentOwner.current = workInProgress;let nextChildren;// 有任何错误捕获, 但没有配置这个api的时候// 这个 getDerivedStateFromError 生命周期的api和 componentDidCatch 有区别, 后者在下次更新的时候处理,中间可能instance不存在(因为出错了)// 就继续可能引发在这个class component上面设置的 ref拿到一个null, 操作ref的时候就会出现错误// 在前者这个新的生命周期的api中, 在本次渲染中,生成 state, 渲染出属性, 这样对于 instance 对象依然存在 对应 ref 就可以拿到实际的对象if (didCaptureError &&typeof Component.getDerivedStateFromError !== 'function') {// If we captured an error, but getDerivedStateFrom catch is not defined,// unmount all the children. componentDidCatch will schedule an update to// re-render a fallback. This is temporary until we migrate everyone to// the new API.// TODO: Warn in a future release.nextChildren = null;if (enableProfilerTimer) {stopProfilerTimerIfRunning(workInProgress);}} else {if (__DEV__) {ReactCurrentFiber.setCurrentPhase('render');nextChildren = instance.render();if (debugRenderPhaseSideEffects ||(debugRenderPhaseSideEffectsForStrictMode &&workInProgress.mode & StrictMode)) {instance.render();}ReactCurrentFiber.setCurrentPhase(null);} else {// 调用 render 方法,计算出新的 childrennextChildren = instance.render();}}// React DevTools reads this flag.workInProgress.effectTag |= PerformedWork; // 增加 PerformedWork// 不是第一次渲染,并且有错误捕获if (current !== null && didCaptureError) {// If we're recovering from an error, reconcile without reusing any of// the existing children. Conceptually, the normal children and the children// that are shown on error are two different sets, so we shouldn't reuse// normal children even if their identities match.forceUnmountCurrentAndReconcile(current,workInProgress,nextChildren,renderExpirationTime,);} else {// 正常情况调用 调和 childrenreconcileChildren(current,workInProgress,nextChildren,renderExpirationTime,);}// Memoize state using the values we just used to render.// TODO: Restructure so we never read values from the instance.workInProgress.memoizedState = instance.state;// The context might have changed so we need to recalculate it.if (hasContext) {invalidateContextProvider(workInProgress, Component, true);}return workInProgress.child; // 把 render 方法渲染出来的第一个子节点 返回给 nextUnitOfWork, 就可以在 workLoop 中继续进行更新的流程 }
-
简单总结
- 以上是更新 class component 的整体流程
- 一开始要使用
constructClassInstance
创建 class instance - 内部会根据不同情况调用不同方法
- 并且要调用
mountClassInstance
来挂载 - 如果是第一次渲染被中断的情况
- 如果存在 instance 则重复使用 instance
- 它调用的生命周期方法仍然是 第一次渲染的生命周期方法
- 也就是
componentDidMount
- 如果不是第一次渲染的情况
- 调用 updateClassInstance 方法
- 这种会最终调用
componentDidUpdate
方法
- 它们中间的流程类似
- 判断各种情况,创建新的 instance 或 复用之前的
- 通过
processUpdateQueue
来获取新的 state - 会把它赋值到 instance 和 fiber 上面进行记录
- 最终都会调用
finishClassComponent
- 这里面做一些错误判断的处理
- 以及是否可以跳过更新的过程
- 还有重新调和子节点 (通用流程)
相关文章:

React16源码: React中的updateClassComponent的源码实现
ClassComponent 的更新 1 ) 概述 在 react 中 class component,是一个非常重要的角色它承担了 react 中 更新整个应用的API setStateforceUpdate 在react当中,只有更新了state之后,整个应用才会重新进行渲染在 class component 中…...

Mybatis 动态SQL(set)
我们先用XML的方式实现 : 把 id 为 13 的那一行的 username 改为 ip 创建一个接口 UserInfo2Mapper ,然后在接口中声明该方法 package com.example.mybatisdemo.mapper; import com.example.mybatisdemo.model.UserInfo; import org.apache.ibatis.annotations.*; import jav…...

Ubuntu18.04在线镜像仓库配置
在线镜像仓库 1、查操作系统版本 rootubuntu:~# lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 18.04.5 LTS Release: 18.04 Codename: bionic 2、原文件备份 sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak 3、查…...

多数据源配置H2 Mysql
H2->Mysql数据迁移 需求背景环境说明实现过程配置调整原配置修改配置 代码调整新增DatasourceConfig配置类使用secondaryJdbcTemplate 需求背景 最近有一需求,原本项目中由于某些原因使用嵌入式数据库H2,鉴于嵌入式数据库可靠性以及不方便管理等因素…...

【ASP.NET Core 基础知识】--路由和请求处理--路由概念(一)
在Web应用中,路由是一个至关重要的概念,它负责将用户的请求映射到相应的处理程序,以确保正确的页面或资源被呈现给用户。通过将用户请求与适当的处理程序关联起来,使得应用能够以有序和可维护的方式响应用户的操作。 一、ASP.NET…...

【Unity】RayMarching体积云理论学习
RayMarching 体积云 RayMarching 是一种处理体积物体的方法 RayMarching 体积云的制作是基于屏幕后处理 屏幕空间重建世界坐标 目的是把屏幕坐标的每一个像素点转化成Unity世界坐标,可以得到射线的方向 如何在需要渲染的物体或者场景中使用RayMarchingÿ…...

物联网与智慧城市的无界未来:如何打破传统束缚,开启智能生活新篇章
目录 一、物联网:连接万物的技术革命 1、物联网的发展历程 2、物联网的核心技术 二、智慧城市:未来城市的蓝图与挑战 1、智慧城市的蓝图 2、智慧城市建设面临的挑战 3、应对挑战的措施 三、物联网与智慧城市的融合:打破传统束缚&…...

nodejs下载安装
一、node下载安装 官网下载 官网 根据自己电脑系统选择合适的版本进行下载,我这里选择window 64 位 下载完点击安装 打开cmd查看安装 此处说明下:新版的Node.js已自带npm,安装Node.js时会一起安装,npm的作用就是对Node.js…...

从零学Java - Lambda表达式
Lambda 表达式 文章目录 Lambda 表达式什么是 Lambda 表达式?怎么使用?1 基本语法:2 箭头符号:3 代码演示:4 注意事项 函数式接口1 什么是函数式接口2 常见函数式接口 方法引用(了解)1 什么是方法引用 什么是 Lambda 表达式? Lambda表达式:特殊的匿名内部类&…...

RV1103与FPGA通过MIPI CSI-2实现视频传输,实现网络推流
RV1103与FPGA通过MIPI CSI-2实现视频传输,实现网络推流。 一:图像格式 支持图像格式如下: [0]: NV16 (Y/CbCr 4:2:2) Size: Stepwise 64x64 - 2304x1296 with step 8/8 [1]: NV61 (Y/CrCb 4:2:2) Size: Stepwise 64x64 - 2304x1296 with …...

力扣62. 不同路径
动态规划 思路: 定义 dp[r][c] 为到达坐标 (r, c) 的路径数: 它只能有同一行左边相邻方格向右到达或者同一列上方相邻方格向下到达;状态转移方程: dp[r][c] dp[r][c - 1] dp[r - 1][c]初始状态 dp[0][0] 1第一行的路径数是 1第…...

使用Element-Plus 加载style
vue-chrome-extension 简介 chrome扩展开发插件基于vue3、ts、Element Plus、Webpack5、axios、less开发 支持content快速调用chrome对象及axios 详看 pages/content/app.vue 开箱即用chrome插件 特性 基础框架:使用 Vue3/Element PlusTypeScript: 应用程序级 J…...

Kafka常见指令及监控程序介绍
kafka在流数据、IO削峰上非常有用,以下对于这款程序,做一些常见指令介绍。 下文使用–bootstrap-server 10.0.0.102:9092,10.0.0.103:9092,10.0.0.104:9092 需自行填写各自对应的集群IP和kafka的端口。 该写法 等同 –bootstrap-server localhost:9092 …...

Docker 仓库管理
Docker 仓库管理 仓库(Repository)是集中存放镜像的地方。以下介绍一下 Docker Hub。当然不止 docker hub,只是远程的服务商不一样,操作都是一样的。 Docker Hub 目前 Docker 官方维护了一个公共仓库 Docker Hub。 大部分需求…...

LeetCode-410.分割数组的最大值
原题链接:https://leetcode.cn/problems/split-array-largest-sum/description 题面 给定一个非负整数数组 nums 和一个整数 k ,你需要将这个数组分成 k 个非空的连续子数组。设计一个算法使得这 k 个子数组各自和的最大值最小。 思路 数组定义ÿ…...

Redis和RediSearch的安装及使用
1. 安装要求 ReadiSearch要求Redis的版本在6.0以上RediSearch 要求使用 GNU Make 4.0 或更高版本 2. Redis的安装 查看redis的版本: redis-server --version或者,如果你已经启动了Redis服务器,你也可以使用redis-cli工具来获取版本信息&a…...

面向对象进阶--接口2
JDK8开始接口中新增的方法 接口中可以定义有方法体的方法(默认、静态)。 使用默认方法的作用:解决接口升级的问题。 接口中默认方法的定义格式: public default返回值类型 方法名(参数列表){} 接口中默…...

提升认知,推荐15个面向开发者的中文播客
前言 对于科技从业者而言,无论是自学成才的程序员,还是行业资深人士,终身学习是很有必要的,尤其是在这样一个技术快速迭代更新的时代。 作为一个摆脱了时间和空间限制的资讯分享平台,播客(Podcast&#x…...

数据分析-Pandas如何整合多张数据表
数据分析-Pandas如何整合多张数据表 数据表,时间序列数据在数据分析建模中很常见,例如天气预报,空气状态监测,股票交易等金融场景。数据分析过程中表格重整,重新调整,重塑数据表是很重要的技巧,…...

配置redis挂载
1. 暂停和删除redis 2.创建文件夹 /usr/local/software/redis/6379/conf/ /usr/local/software/redis/6379/data/ 把redis-conf文件上传到conf文件夹中 3.配置网络 docker network create --driver bridge --subnet172.18.12.0/16 --gateway172.18.1.1 wn_docker_net 4.运…...

C++ 实现游戏(例如MC)键位显示
效果: 是不是有那味儿了? 显示AWSD,空格,Shift和左右键的按键情况以及左右键的CPS。 彩虹色轮廓,黑白填充。具有任务栏图标,可以随时关闭字体是Minecraft AE Pixel,如果你没有装(大…...

力扣hot100 合并两个有序链表 递归 双指针
Problem: 21. 合并两个有序链表 文章目录 💖 递归思路 💖 双指针 💖 递归 思路 👨🏫 参考地址 n , m n,m n,m 分别为 list1 和 list2 的元素个数 ⏰ 时间复杂度: O ( n m ) O(nm) O(nm) 🌎 空间复杂…...

10个常用python自动化脚本
大家好,Python凭借其简单和通用性,能够为解决每天重复同样的工作提供最佳方案。本文将探索10个Python脚本,这些脚本可以帮助自动化完成任务,提高工作效率。无论是开发者、数据分析师还是仅仅想简化工作流程的普通用户,…...

C++中函数的默认参数(缺省参数)
一、函数默认参数的概念 在函数声明时,预先对函数参数进行赋值,该参数即为函数的默认参数,也叫缺省参数。 如下函数func1包含默认参数,若调用函数func1时没有给函数传入实参,则默认实参为10086 void func1(int a 1…...

在线扒站网PHP源码-在线扒站工具网站源码
源码介绍 这是一款在线的网站模板下载程序,也就是我们常说的扒站工具,利用它我们可以很轻松的将别人的网站模板样式下载下来,这样就可以大大提高我们编写前端的速度了!注:扒取的任何站点不得用于商业、违法用途&#…...

vue+elementUI el-select 中 没有加clearable出现一个或者多个×清除图标问题
1、现象:下方截图多清除图标了 2、在全局common.scss文件中加一个下方的全局样式noClear 3、在多清除图标的组件上层div加noClear样式 4、清除图标去除成功...

【Python从入门到进阶】47、Scrapy Shell的了解与应用
接上篇《46、58同城Scrapy项目案例介绍》 上一篇我们学习了58同城的Scrapy项目案例,并结合实际再次了项目结构以及代码逻辑的用法。本篇我们来学习Scrapy的一个终端命令行工具Scrapy Shell,并了解它是如何帮助我们更好的调试爬虫程序的。 一、Scrapy Sh…...

【ARM 嵌入式 编译系列 2.2 -- GCC 编译参数学习 assembler-with-cpp 使用介绍】
请阅读【嵌入式开发学习必备专栏 之 ARM GCC 编译专栏】 文章目录 GCC 编译选项 assembler-with-cpp GCC 编译选项 assembler-with-cpp 在 rt-thread 的编译脚本中经常会看到下面编译参数: AFLAGS -c DEVICE -x assembler-with-cpp -Wa,-mimplicit-itthumb a…...

深入理解java对象的内存布局
概述: 在HotSpot虚拟机里,对象在堆内存中的存储布局可以划分为三个部分:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。 在HotSpot虚拟机里,…...

MetaGPT中提到的SOP
MetaGPT框架中的提及的SOP概念指的是什么,有什么优点和缺点,为什么要使用SOP? 在MetaGPT框架中,SOP(Set of Procedures)指的是一套标准化的流程和步骤,用于指导模型完成特定任务。SOP可以帮助模型更好地理…...