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.pswp.cn/web/63451.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/63451.shtml
英文地址,請注明出處:http://en.pswp.cn/web/63451.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

使用DynadotAPI購買域名清倉列表中的過期域名

前言 Dynadot是通過ICANN認證的域名注冊商&#xff0c;自2002年成立以來&#xff0c;服務于全球108個國家和地區的客戶&#xff0c;為數以萬計的客戶提供簡潔&#xff0c;優惠&#xff0c;安全的域名注冊以及管理服務。 Dynadot平臺操作教程索引&#xff08;包括域名郵箱&…

js分頁功能

先聲明些全局變量方便我們在下面的代碼中使用 //一頁有多少條數據 let num 10; //頁碼 let k 0; //總頁數 let divide; // 用來判斷顯示哪幾頁的頁數 let page_num 0; // 聲明一個用于接數據的變量 let datas; // 聲明一個用于接數據的變量 let data; //一頁有多少條數據 l…

CMake Do‘s and Don‘ts (行為準則)

CMake Dos and Donts {行為準則} 1. General2. Modules3. ProjectsReferences Effective Modern CMake https://gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1 Do’s and Don’ts https://cliutils.gitlab.io/modern-cmake/chapters/intro/dodonot.html dos and …

驗證的分類及相關工具

目錄 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 新…

串口通信和SPI通信詳解

0、背景 在現代嵌入式系統中&#xff0c;通信是不同模塊之間交換數據的核心。串口通信和 SPI&#xff08;串行外設接口&#xff09;是兩種常見的通信方式&#xff0c;它們各自有獨特的優勢和適用場景。 1、串口通信 1.1、串口通信概念 串口通信是一種常見的異步串行通信協議…

javase-17、API.數學相關

一、Math類 Math類提供了大量的靜態方法來便于我們實現數學計算&#xff0c;如求絕對值、取最大或最小值等。 https://doc.qzxdp.cn/jdk/17/zh/api/java.base/java/lang/Math.html 所在模塊&#xff1a;java.base所在包&#xff1a; java.lang static double abs(double a)…

答題考試系統v1.6.1高級版源碼分享+uniapp+搭建測試環境

一.系統介紹 一款基于FastAdminThinkPHPUniapp開發的小程序答題考試系統&#xff0c;支持多種試題類型、多種試題難度、練題、考試、補考模式&#xff0c;提供全部前后臺無加密源代碼&#xff0c;支持私有化部署 二.測試環境 系統環境&#xff1a;CentOS、 運行環境&#x…

淺談倉頡語言的優劣

倉頡語言&#xff0c;作為華為自研的新一代編程語言&#xff0c;以其高效、安全、現代化的特點&#xff0c;引起了廣泛的關注。 倉頡語言的優勢 高效并發 倉頡語言的一大亮點是其輕松并發的能力。它實現了輕量化用戶態線程和并發對象庫&#xff0c;使得高效并發變得輕松。倉頡…

Sass系統數據隔離的三種方式

1.完全獨立的數據庫 為每一個租戶單獨部署一個數據庫 優點&#xff1a;達到了真正的按租戶進行隔離&#xff0c;不同租戶之間相互沒有影響&#xff0c;可以針對一些特殊租戶例如大客戶做一些定制化的開發&#xff0c;計費相對簡單&#xff0c;按照資源使用進行計費。 缺點&…

FFmpeg 主要結構體剖析

FFmpeg 探索之旅 FFmpeg 主要結構體剖析 FFmpeg 探索之旅前言1、AVFormatContext2、AVCodecContext3、AVCodec4、AVStream5、AVPacket6、AVFrame7、AVCodecParameters7、SwsContext8、AVIOContext9、AVRational 總結 前言 嘿&#xff0c;各位小伙伴&#xff01;在如今這個多媒…

經典電荷泵/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…