React源码02 - 基础知识 React API 一览

1. JSX到JavaScript的转换

<div id="div" key="key"><span>1</span><span>2</span>
</div>
React.createElement("div", // 大写开头会当做原生dom标签的字符串,而组件使用大写开头时,这里会成为变量引用{ id: "div", key: "key" },React.createElement("span", null, "1"),React.createElement("span", null, "2")
);
createElement(type, config, children) {// 从用户传入的 config 中把4种内置的属性 key、ref、self、source 单独挑出来,config 中剩余的参数作为用户的 props。// 然后返回使用 ReactElement 创建的 element 对象。
return ReactElement( type,  key,  ref,  self,  source,  ReactCurrentOwner.current,  props, );
}

2. ReactElement

const ReactElement = function(type, key, ref, self, source, owner, props) {const element = {// This tag allows us to uniquely identify this as a React Element$$typeof: REACT_ELEMENT_TYPE,// Built-in properties that belong on the elementtype: type, // 可能是原生dom标签字符串如'span',也可能是一个class类(class组件),还可能是一个function(函数式组件),也可能是 forwardRef 返回的对象,或者 symbol 标记等 key: key,ref: ref,props: props,// Record the component responsible for creating this element._owner: owner,};if (__DEV__) {// 略}return element;
};
React.createElement("div",{ id: "div", key: "key" },React.createElement("span", null, "1"),React.createElement("span", null, "2")
);// 于是最初的 jsx 经过 React.createElement() 后成为了下面的对象树,
// 也是函数式组件返回的东西,也是 class 组件组件 render() 方法返回的东西
element = {$$typeof: REACT_ELEMENT_TYPE,type: type,key: key,ref: ref,props: {userProps1: userProps1,// ... 用户其他的自定义propschildren: [{$$typeof: REACT_ELEMENT_TYPE,type: type,key: key,ref: ref,props: props,_owner: owner,}, {$$typeof: REACT_ELEMENT_TYPE,type: type,key: key,ref: ref,props: props,_owner: owner,}]},_owner: owner,
};

3. 基类 React.Component

Component 类可能不是想象中那样用于渲染子组件什么的,只是做一些绑定工作:

function Component(props, context, updater) {this.props = props;this.context = context;// If a component has string refs, we will assign a different object later.this.refs = emptyObject;// We initialize the default updater but the real one gets injected by the// renderer.this.updater = updater || ReactNoopUpdateQueue;
}// PureComponent 继承了 Component
function PureComponent(props, context, updater) {this.props = props;this.context = context;// If a component has string refs, we will assign a different object later.this.refs = emptyObject;this.updater = updater || ReactNoopUpdateQueue;
}
// pureComponentPrototype.isPureReactComponent = true;// 常规的 setState,这里只是入队列
Component.prototype.setState = function(partialState, callback) {invariant(typeof partialState === 'object' ||typeof partialState === 'function' ||partialState == null,'setState(...): takes an object of state variables to update or a ' +'function which returns an object of state variables.',);this.updater.enqueueSetState(this, partialState, callback, 'setState');
};// 可主动强制更新,这里也只是入队列
// enqueueForceUpdate 内部实现了 ”重载”
Component.prototype.forceUpdate = function(callback) {this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
};

4. createRef & ref

ref 用于获取 dom 节点或者 class component 的实例。
有三种用法,第一种 string 方法不推荐使用,后面在 React 17 中应该会被废弃:

import React from 'react'export default class RefDemo extends React.Component {constructor() {super()this.objRef = React.createRef()// { current: null }}componentDidMount() {setTimeout(() => {this.refs.stringRef.textContent = 'string ref got'this.methodRef.textContent = 'method ref got'this.objRef.current.textContent = 'obj ref got'}, 1000)}render() {return (<><p ref="stringRef">span1</p><p ref={ele => (this.methodRef = ele)}>span3</p><p ref={this.objRef}>span3</p></>)}
}// export default () => {
//   return <div>Ref</div>
// }

Object.seal() 密封,阻止目标对象上增删属性,并且关闭所有属性的 configurable,但仍可以修改现有的、是 writable 的属性。
Object.freeze() 冻结,比密封更严格,会将 writable 也关闭,意味着现有属性“不可以”修改。但如果属性本身是个引用类型,比如 const object = {a: 1, b: []},那么即使冻结 object 后,object.b.push(666) 也是可以的。
另外,冻结也会冻结目标对象上的 prototype 原型对象。

createRef 源码:

import type {RefObject} from 'shared/ReactTypes';// an immutable object with a single mutable value
export function createRef(): RefObject {const refObject = {current: null,};if (__DEV__) {Object.seal(refObject);}return refObject;
}

5. forwardRef

字面意思,转发 ref ?为什么 ref 需要转发,不能像上面那样直接使用?

dom 节点或者 class component,是可以由 react 在组件渲染之后把实例绑定(或提供)至我们指定的“容器”中,之后我们就可以从“容器”中引用刚才的实例,进行想要的操作。

React.createRef() 返回的就是 { current: null },这个对象就可以理解为一个“容器”,我们以在 jsx 上声明的方式,提供给 react,渲染之后返回我们想要的实例引用。

image

然而 function 函数式组件并没有实例,就是个函数。所以外部用户无差别地尝试为组件提供 ref “容器”希望回头能拿到实例时,如果遇到 function 组件,则会失败、报错。而这种报错可以通过转发 ref 来避免,因为 function 组件没有所谓的实例,但内部至少返回了 dom 或者另外的 class 组件吧,所以把 ref 转发给它们即可。
即外部用户最终拿到的实例引用,其实是函数式组件内层的实例。

自己的组件可能知道报错,不会去直接试图获取 function 组件的 ref,但如果是作为第三方组件库提供给其他 react 用户来调用,则要使用 forwardRef 来转发用户的诉求,并实现他们。

import React from 'react';class App extends React.Component {render() {return <div>div</div>;}
}const TargetComponent = React.forwardRef((props, ref) => (<input type="text" ref={ref}/>
));export default class Comp extends React.Component {constructor() {super();this.ref = React.createRef();this.ref2 = React.createRef();}componentDidMount() {// 虽然还是声明在 TargetComponent 函数组件上,但最终拿到了有效的实例引用,即内部的 dom 节点this.ref.current.value = 'ref get input';console.log('this.ref', this.ref);console.log('this.ref2', this.ref2);}render() {return <><TargetComponent ref={this.ref}/><App ref={this.ref2} /></>;}
}

React.forwardRef() 源码:

export default function forwardRef<Props, ElementType: React$ElementType>(render: (props: Props, ref: React$Ref<ElementType>) => React$Node,
) {if (__DEV__) {// 用户不按规定的使用会抛出异常信息}return {$$typeof: REACT_FORWARD_REF_TYPE,render,};
}

可以看到向 forwardRef 传入的 render 函数至少没在这里被调用,只是用对象包了一层,并增加了一个 $$typeof 属性,值是个 symbol。所以上面例子中声明实际等价于:

const TargetComponent = {$$typeof: REACT_FORWARD_REF_TYPE,render: (props, ref) => (<input type="text" ref={ref}/>)
};// 经过 React.createElement() 创建出的 element:
const element = {// This tag allows us to uniquely identify this as a React Element$$typeof: REACT_ELEMENT_TYPE,type: TargetComponent,key: null,ref: React.createRef(),props: {},// Record the component responsible for creating this element._owner: owner,
};

6. Context

使用 context 也有两种方式,childContextType 和 createContext。
childContextType 是老的方式,在将来的 React 17 中应该会被废弃,所以优先使用 createContext。

import React from 'react'const MyContext = React.createContext('default');
const { Provider, Consumer } = MyContext;class Parent extends React.Component {state = {newContext: '123',};render() {return (<><div><label>newContext:</label><inputtype="text"value={this.state.newContext}onChange={e => this.setState({ newContext: e.target.value })}/></div><Provider value={this.state.newContext}>{this.props.children}</Provider></>)}
}class Parent2 extends React.Component {render() {return this.props.children}
}function Child1(props, context) {console.log(MyContext);console.log(context);return <Consumer>{value => <p>newContext: {value}</p>}</Consumer>
}export default () => (<Parent><Parent2><Child1 /></Parent2></Parent>
);

React.createContext() 源码:
返回的 context 对象中有 $$typeof: REACT_CONTEXT_TYPE ,且有 Provider 和 Consumer,Provider 只是用对象包了一下原 context,添加了 $$typeof: REACT_PROVIDER_TYPE 属性;而 Consumer 压根就是引用原 context。有点俄罗斯套娃的感觉,能想到的就是 $$typeof 会作为 react 更新时判断不同类型的依据。而套娃的操作,可能就是为了方便操作 context,引来引去总能找到那个 context。


export function createContext<T>(defaultValue: T,calculateChangedBits: ?(a: T, b: T) => number,
): ReactContext<T> {if (calculateChangedBits === undefined) {calculateChangedBits = null;} else {if (__DEV__) {// 略);}}const context: ReactContext<T> = {$$typeof: REACT_CONTEXT_TYPE,_calculateChangedBits: calculateChangedBits,// As a workaround to support multiple concurrent renderers, we categorize// some renderers as primary and others as secondary. We only expect// there to be two concurrent renderers at most: React Native (primary) and// Fabric (secondary); React DOM (primary) and React ART (secondary).// Secondary renderers store their context values on separate fields._currentValue: defaultValue,_currentValue2: defaultValue,// These are circularProvider: (null: any),Consumer: (null: any),};context.Provider = {$$typeof: REACT_PROVIDER_TYPE,_context: context,};if (__DEV__) {// 异常处理} else {context.Consumer = context;}return context;
}

打印 React.createContext() 返回的 context 对象,验证套娃操作:


image

7. ConcurrentMode

在 React 16.6 提出,让 react 整体渲染过程可以根据优先级排列,可以任务调度、可以中断渲染过程等。来提高渲染性能,减少页面卡顿。

flushSync 使用优先级最高的方式进行更新,用来提高 this.setState 优先级。

使用 ConcurrentMode 包裹的组件都是低优先级的,所以为了演示高低优先级带来的区别感受,对比使用 flushSync。

例子中使用 flushSync 时,setState 优先级最高,基本是立即更新,这也导致动画卡顿明显,因为 200ms setState 间隔太快了,可能还没来得及渲染完,又要更新。因此使用 ConcurrentMode 把更新的优先级降低,从而不会频繁更新动画,显得流畅许多。

import React, { ConcurrentMode } from 'react'
import { flushSync } from 'react-dom'import './index.css'class Parent extends React.Component {state = {async: true,num: 1,length: 20000,}componentDidMount() {this.interval = setInterval(() => {this.updateNum()}, 200)}componentWillUnmount() {// 别忘了清除intervalif (this.interval) {clearInterval(this.interval)}}updateNum() {const newNum = this.state.num === 3 ? 0 : this.state.num + 1if (this.state.async) {this.setState({num: newNum,})} else {flushSync(() => {this.setState({num: newNum,})})}}render() {const children = []const { length, num, async } = this.statefor (let i = 0; i < length; i++) {children.push(<div className="item" key={i}>{num}</div>,)}return (<div className="main">async:{' '}<inputtype="checkbox"checked={async}onChange={() => flushSync(() => this.setState({ async: !async }))}/><div className="wrapper">{children}</div></div>)}
}export default () => (<ConcurrentMode><Parent /></ConcurrentMode>
)
@keyframes slide {0% {margin-left: 0;/* transform: translateX(0); */}50% {margin-left: 200px;/* transform: translateX(200px); */}100% {margin-left: 0;/* transform: translateX(0); */}
}.wrapper {width: 400px;animation-duration: 3s;animation-name: slide;animation-iteration-count: infinite;display: flex;flex-wrap: wrap;background: red;
}.item {width: 20px;height: 20px;line-height: 20px;text-align: center;border: 1px solid #aaa;
}

React.ConcurrentMode 源码:
没错,源码就是一个 Symbol 符号,显示 react 内部会判断该标记然后做些什么。

React.ConcurrentMode = REACT_CONCURRENT_MODE_TYPE;

不难想象,经过 createElement() 创建出的 reactElement 树节点应该会是这样:

element = {// This tag allows us to uniquely identify this as a React Element$$typeof: REACT_ELEMENT_TYPE,// Built-in properties that belong on the elementtype: REACT_CONCURRENT_MODE_TYPE, // 看这里key: null,ref: null,props: props,// Record the component responsible for creating this element._owner: owner,
};

8. Suspense

Suspense 是一种在组件所依赖的数据尚未加载 ok 时,负责和 react 进行沟通,展示中间态的机制。
react 将会等待数据加载完成然后进行 UI 更新。

传统做法是在组件第一次挂载之后,即 componentDidMount() 或 useEffect() 中加载数据。即:

  1. Start fetching
  2. Finish fetching(然后调用 setState)
  3. Start rendering(再次渲染)

而 Suspense 也是先获取数据,(而且可以比传统做法更早一步,在第一次渲染之前),接着立马就开始第一次渲染(甚至在网络请求被实际发出前),遇到悬而未决即数据尚未获取,则挂起(suspends)该组件,跳过,然后继续渲染 element 树中其他的组件,如果又遇到还没搞定的 Suspense,则继续挂起并跳过。

  1. Start fetching
  2. Start rendering
  3. Finish fetching

Suspense 具体使用时,有一个“边界”概念,只有当一个 Suspense 内部的所有“挂起”都落地后,Suspense 才会停止展示 fallback 中间态,然后一并展示内部的 UI,因此可以通过合理增添 Suspense 边界来控制这种粒度。

// 用于懒加载的组件:
import React from 'react'
export default () => <p>Lazy Comp</p>
import React, { Suspense, lazy } from 'react'const LazyComp = lazy(() => import('./lazy.js'))let data = ''
let promise = ''
function requestData() {if (data) return dataif (promise) throw promisepromise = new Promise(resolve => {setTimeout(() => {data = 'Data resolved'resolve()}, 2000)})throw promise
}function SuspenseComp() {const data = requestData() // 数据尚未加载完成时,该组件的渲染会被挂起。return <p>{data}</p>
}export default () => (<Suspense fallback="loading data"><SuspenseComp /><LazyComp /></Suspense>
)

Suspense 源码:

  Suspense: REACT_SUSPENSE_TYPE // 又是一个 symbol 常量

lazy 源码:
_ctor 就是调用 lazy() 时传入的函数,该函数应返回一个 Thenable(具有then方法的对象)。react 渲染到该组件时,会调用 _ctor 函数。
_status 用于记录当前 Thenable 的状态, -1 代表尚未解决,对应到 promise 中也就是 pending 状态。
_result 用于存放 resolve 后的结果。

import type {LazyComponent, Thenable} from 'shared/ReactLazyComponent';import {REACT_LAZY_TYPE} from 'shared/ReactSymbols';export function lazy<T, R>(ctor: () => Thenable<T, R>): LazyComponent<T> {return {$$typeof: REACT_LAZY_TYPE,_ctor: ctor,// React uses these fields to store the result._status: -1,_result: null, };
}

另外,关于 Suspense 能解决异步竞态问题的理解:

异步请求带来的竞态问题,本质是因为异步请求和 React 分别处于各自的生命周期,二者并未相互同步、一一对应。往往需要等待一段时间,在数据返回之后才去调用 setState,如果快速操作 UI,多次发送相同请求时,由于异步请求时间的不确定性,可能第一条请求反而比第二条同样的请求,响应的更慢,这将导致页面展示了“旧”的数据,带来了混乱。

而使用 Suspense 时,是在UI触发之后,立即调用 setState 尝试去更新数据,如果数据还没返回,则 Suspense 会挂起(suspend)并展现 fallback 中间态。但这个等待正确数据的时间管理工作,已经交给 Suspense 内部去处理了,setState 的使命已经立即完成。暂时理解为脏活累活交给 Suspense 自行消化。

Suspense 结合 useTransition 使用更佳:

This scenario (Receded → Skeleton → Complete) is the default one. However, the Receded state is not very pleasant because it “hides” existing information. This is why React lets us opt into a different sequence (Pending → Skeleton → Complete) with useTransition.
When we useTransition, React will let us “stay” on the previous screen — and show a progress indicator there. We call that a Pending state. It feels much better than the Receded state because none of our existing content disappears, and the page stays interactive.

9. Hooks

hooks 用于 function 函数式组件,内部没有 class component 中那样用来维持内部状态的 this 对象,也没有典型的生命周期方法。

一个非常简单的例子,hooks 是一个大块的内容,这里不表。

/*** 必须要react和react-dom 16.7以上*/import React, { useState, useEffect } from 'react';export default () => {const [name, setName] = useState('jokcy');useEffect(() => {console.log('component update');return () => {console.log('unbind');};}, []);return (<><p>My Name is: {name}</p><input type="text" value={name} onChange={e => setName(e.target.value)}/></>);
}

useState 源码:
useEffect 等 use* 类似,都是在调用 dispatcher 上的方法。后期会再深入研究 hooks 内层的源码:

export function useState<S>(initialState: (() => S) | S) {const dispatcher = resolveDispatcher();return dispatcher.useState(initialState);
}
// 局部
function resolveDispatcher() {const dispatcher = ReactCurrentOwner.currentDispatcher;invariant(dispatcher !== null,'Hooks can only be called inside the body of a function component.',);return dispatcher;
}
/*** Keeps track of the current owner.** The current owner is the component who should own any components that are* currently being constructed.*/
const ReactCurrentOwner = {/*** @internal* @type {ReactComponent}*/current: (null: null | Fiber), // 代表当前正在被构建的组件实例currentDispatcher: (null: null | Dispatcher),
};export default ReactCurrentOwner;

10. Children

Children 上的方法有:

Children: {map,forEach,count,toArray,only,
},

React.Children.map() 中 map 可以遍历 child 并映射展开:

import React from 'react'function ChildrenDemo(props) {console.log(props.children)console.log(React.Children.map(props.children, c => [c, [c, c]]))return props.children
}export default () => (<ChildrenDemo><span>1</span><span>2</span></ChildrenDemo>
)

map 遍历 children 时有个 contextPool 对象常量池的概念,用于复用对象。以节省递归遍历 child 时多次对象创建和 GC 回收的开销。

React 这么实现主要是两个目的:

  1. 拆分 map 出来的数组
  2. 因为对 Children 的处理一般在 render 里面,所以会比较频繁,所以设置一个对象池子减少声明和 GC 的开销。


    image

11. Other

  • memo ,用于 function component,功能上对标 class component 中的 pureComponent

浅层源码中,也没多少东西,只是返回了一个带有 $$typeof 标记的对象及 typecompare ,memo 这种返回类似前面 createRef 的返回:

export default function memo<Props>(type: React$ElementType,compare?: (oldProps: Props, newProps: Props) => boolean,
) {if (__DEV__) {if (!isValidElementType(type)) {warningWithoutStack(false,'memo: The first argument must be a component. Instead ' +'received: %s',type === null ? 'null' : typeof type,);}}return {$$typeof: REACT_MEMO_TYPE,type,compare: compare === undefined ? null : compare,};
}
  • FragElement(简写方式是空标签 <></>

最外层源码就是 FragElement: REACT_FRAGMENT_TYPE
是临时节点,因为 React 要求不能直接返回多个兄弟节点,要么“包”一层,要么返回数组。而 FragElement 就是用来“包”一层的,相比于用真实的 div 去“包”一层,FragElement 并不会实际被创建。

  • cloneElement

克隆一个节点,源码基本和 createElement 一样,只是第一个参数从 type 变为了 element ,实际即要克隆的 element 对象上属性,然后把参数丢给 ReactElement() 来返回一个新的 element 对象:

/*** Clone and return a new ReactElement using element as the starting point.* See https://reactjs.org/docs/react-api.html#cloneelement*/
export function cloneElement(element, config, children) {invariant(!(element === null || element === undefined),'React.cloneElement(...): The argument must be a React element, but you passed %s.',element,);let propName;// Original props are copiedconst props = Object.assign({}, element.props);// Reserved names are extractedlet key = element.key;let ref = element.ref;// Self is preserved since the owner is preserved.const self = element._self;// Source is preserved since cloneElement is unlikely to be targeted by a// transpiler, and the original source is probably a better indicator of the// true owner.const source = element._source;// Owner will be preserved, unless ref is overriddenlet owner = element._owner;if (config != null) {if (hasValidRef(config)) {// Silently steal the ref from the parent.ref = config.ref;owner = ReactCurrentOwner.current;}if (hasValidKey(config)) {key = '' + config.key;}// Remaining properties override existing propslet defaultProps;if (element.type && element.type.defaultProps) {defaultProps = element.type.defaultProps;}for (propName in config) {if (hasOwnProperty.call(config, propName) &&!RESERVED_PROPS.hasOwnProperty(propName)) {if (config[propName] === undefined && defaultProps !== undefined) {// Resolve default propsprops[propName] = defaultProps[propName];} else {props[propName] = config[propName];}}}}// Children can be more than one argument, and those are transferred onto// the newly allocated props object.const childrenLength = arguments.length - 2;if (childrenLength === 1) {props.children = children;} else if (childrenLength > 1) {const childArray = Array(childrenLength);for (let i = 0; i < childrenLength; i++) {childArray[i] = arguments[i + 2];}props.children = childArray;}return ReactElement(element.type, key, ref, self, source, owner, props);
}
  • createFactory

如果时候 jsx 语法,而不是手动用 JS 调用 createElement 来创建 element 树的话,基本不会用到该方法,createFactory 就只是包了一层,省的每次创建同样类型的 element,都传入第一个 type 参数了:

/*** Return a function that produces ReactElements of a given type.* See https://reactjs.org/docs/react-api.html#createfactory*/
export function createFactory(type) {const factory = createElement.bind(null, type);// Expose the type on the factory and the prototype so that it can be// easily accessed on elements. E.g. `<Foo />.type === Foo`.// This should not be named `constructor` since this may not be the function// that created the element, and it may not even be a constructor.// Legacy hook: remove itfactory.type = type;return factory;
}
  • isValidElement

判断一个对象是否是合法的 element:

/*** Verifies the object is a ReactElement.* See https://reactjs.org/docs/react-api.html#isvalidelement* @param {?object} object* @return {boolean} True if `object` is a ReactElement.* @final*/
export function isValidElement(object) {return (typeof object === 'object' &&object !== null &&object.$$typeof === REACT_ELEMENT_TYPE);
}


喜欢的朋友记得点赞、收藏、关注哦!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/63451.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

验证的分类及相关工具

目录 1.验证方法的分类1.1动态验证1.2.静态验证 2.动态验证及相关工具2.1.电路级仿真工具2.2.逻辑仿真工具 3.静态验证及相关工具3.1 形式验证工具3.2 静态时序分析工具 SOC设计中验证包含以下几个方面&#xff1a; 验证原始描述的正确性验证设计的逻辑功能是否符合设计规范的要…

【HarmonyOs学习日志(14)】计算机网络之域名系统DNS

域名系统DNS 域名系统DNS——从域名解析出IP地址 文章目录 域名系统DNS概述域名到IP地址的解析 互联网的域名结构命名标准 域名服务器域名的解析过程 概述 域名系统DNS&#xff08;Domain Name System&#xff09;是互联网使用的命名系统&#xff0c;用来把便于人们使用的机器…

【Python】pandas库---数据分析

大学毕业那年&#xff0c;你成了社会底层群众里&#xff0c;受教育程度最高的一批人。 前言 这是我自己学习Python的第四篇博客总结。后期我会继续把Python学习笔记开源至博客上。 上一期笔记有关Python的NumPy数据分析&#xff0c;没看过的同学可以去看看&#xff1a;【Pyt…

【人工智能学习之HDGCN18关键点修改】

【人工智能学习之HDGCN18关键点修改】 训练部分修改部分 训练部分 请参考文章&#xff1a;【人工智能学习之HDGCN训练自己的数据集】 修改部分 参考源码中25关键点的区域划分&#xff0c;我们将18关键点划分为&#xff1a; 头部&#xff1a; 鼻子左眼和左耳右眼和右耳 上肢…

ARCGIS国土超级工具集1.2更新说明

ARCGIS国土超级工具集V1.2版本&#xff0c;功能已增加至47 个。在V1.1的基础上修复了若干使用时发现的BUG&#xff0c;新增了"矢量分割工具"菜单&#xff0c;同时增加及更新了了若干功能&#xff0c;新工具使用说明如下&#xff1a; 一、勘测定界工具栏更新界址点成果…

华为OD --- 流浪地球

华为OD --- 流浪地球 题目独立实现基本思路代码实现 其他答案实现思路代码实现 题目 独立实现 基本思路 1、首先把题目给出的启动机器初始化成数组, 2、用for循环模拟每隔1s更新这个初始化数组的前后两个机器. (源码中的updateTimeCount函数) 3、for循环每次循环后会检查当前…

DataOps驱动数据集成创新:Apache DolphinScheduler SeaTunnel on Amazon Web Services

引言 在数字化转型的浪潮中&#xff0c;数据已成为企业最宝贵的资产之一。DataOps作为一种文化、流程和实践的集合&#xff0c;旨在提高数据管道的质量和效率&#xff0c;从而加速数据从源头到消费的过程。白鲸开源科技&#xff0c;作为DataOps领域的领先开源原生公司&#xf…

【硬件IIC】stm32单片机利用硬件IIC驱动OLED屏幕

之前操作OLED屏幕都是用GPIO模拟IIC去驱动&#xff0c;最近打算用硬件IIC去驱动&#xff0c;于是写下这个demo,在这个过程中遇到一点小坑&#xff0c;记录一下&#xff0c;本文章非小白教程&#xff0c;所以只突出踩到的坑点&#xff0c;文章中涉及到的OLED也是网上资料写烂的&…

python如何自动加空格

首先&#xff0c;需要进行打开的一个pycharm的软件&#xff0c;可进行双击的打开该软件。 可以看到的是在当前的打开的文件中&#xff0c;格式相对较乱一下。格式不对会格式错误。 然后点击菜单栏中的“code”。 在弹出的下拉菜单中选择“reformat code”选项。 可以看到的是在…

【开源免费】基于SpringBoot+Vue.JS网上订餐系统(JAVA毕业设计)

本文项目编号 T 018 &#xff0c;文末自助获取源码 \color{red}{T018&#xff0c;文末自助获取源码} T018&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 新…

答题考试系统v1.6.1高级版源码分享+uniapp+搭建测试环境

一.系统介绍 一款基于FastAdminThinkPHPUniapp开发的小程序答题考试系统&#xff0c;支持多种试题类型、多种试题难度、练题、考试、补考模式&#xff0c;提供全部前后台无加密源代码&#xff0c;支持私有化部署 二.测试环境 系统环境&#xff1a;CentOS、 运行环境&#x…

经典电荷泵/Charge pump——1998.JSSC

电路结构 工作原理 M3 and M4 are the series switches, and M5, M6 switch to the highest voltage. If M5 and M6 are missing, having a large capacitor is of absolute necessity, because must always stay between 2 Vin and 2Vin - Uj to avoid switching on the vert…

Swin transformer 论文阅读记录 代码分析

该篇文章&#xff0c;是我解析 Swin transformer 论文原理&#xff08;结合pytorch版本代码&#xff09;所记&#xff0c;图片来源于源paper或其他相应博客。 代码也非原始代码&#xff0c;而是从代码里摘出来的片段&#xff0c;配上简单数据&#xff0c;以便理解。 当然&…

GPT-Omni 与 Mini-Omni2:创新与性能的结合

近年来&#xff0c;随着人工智能技术的飞速发展&#xff0c;各种模型和平台应运而生&#xff0c;以满足从个人用户到企业级应用的多样化需求。在这一领域&#xff0c;GPT-Omni 和 Mini-Omni2 是两款备受瞩目的技术产品&#xff0c;它们凭借独特的设计和强大的功能&#xff0c;在…

龙迅#LT7911E适用于EDP/DP/TPYE-C转MIPIDSI应用,支持图像处理功能,内置I2C,主应用副屏显示,投屏领域!

1. 描述 LT7911E 是一款高性能 eDP 转 MIPI D-PHY 转换器&#xff0c;旨在将 eDP 源连接到 MIPI 显示面板。 LT7911E 集成了一个符合 eDP1.4 标准的接收器&#xff0c;支持 1.62Gbps 至 5.67Gbps 的输入数据&#xff0c;以 270Mbps 的递增步长&#xff0c;以及一个 2 端口 D…

C语言——实现求出最大值

问题描述&#xff1a;利用C语言自定义函数求出一维数组里边最大的数字 //利用函数找最大数#include<stdio.h>int search(int s[9]) //查找函数 {int i , max s[0] , max_xia 0;for(i0;i<9;i){if(s[i] > max){max_xia i;max s[max_xia];}}return max; } in…

解锁 draw.io 流程图制作工具Docker私有化部署(2/2)

一、draw.io 流程图制作工具简介 &#xff08;一&#xff09;基础介绍 draw.io 是一款备受青睐的开源流程图软件&#xff0c;它有着诸多优点。首先&#xff0c;其界面十分整洁有序&#xff0c;完全没有广告的干扰&#xff0c;并且所有功能都是免费向用户开放的&#xff0c;这一…

[HNCTF 2022 Week1]baby_rsa

源代码&#xff1a; from Crypto.Util.number import bytes_to_long, getPrime from gmpy2 import * from secret import flag m bytes_to_long(flag) p getPrime(128) q getPrime(128) n p * q e 65537 c pow(m,e,n) print(n,c) # 62193160459999883112594854240161159…

docker run命令大全

docker run命令大全 基本语法常用选项基础选项资源限制网络配置存储卷和挂载环境变量重启策略其他高级选项示例总结docker run 命令是 Docker 中最常用和强大的命令之一,用于创建并启动一个新的容器。该命令支持多种选项和参数,可以满足各种使用场景的需求。以下是 docker ru…

Flink2.0未来趋势中需要注意的一些问题

手机打字&#xff0c;篇幅不长&#xff0c;主要讲一下FFA中关于Flink2.0的未来趋势&#xff0c;直接看重点。 Flink Forward Asia 2024主会场有一场关于Flink2.0的演讲&#xff0c;很精彩&#xff0c;官方也发布了一些关于Flink2.0的展望和要解决的问题。 1.0时代和2.0时代避免…