壹 ❀ 引

我在从零开始的react入门教程(八),redux起源与基础用法一文中,介绍了redux的前辈Flux,以及redux关于单项数据更新的基本用法。我们在前文提到,相对Flux支持多个storeredux推荐唯一数据源,也就是使用一个全局Store去掌管所有数据。数据源虽然统一了,但我们要使用Store还是得把Store引入到需要的组件中,比如上文中的Counter组件与Summary组件,毕竟使用dispatch或者监听Store变化都离不开这个数据源,但这就造就了两个问题。

问题一,假设我们有多个组件都依赖了Store数据,组件分布在不同文件夹,或者说我们使用的三方库也依赖了此数据,用一处就得引一次,文件路径的相对关系都是一个不小的麻烦。

问题二,可能有同学就想到,哎,react不是有个概念叫状态提升吗,大不了我在顶层组件引用一次,通过props进行数据传递,但这样就会造成多个组件其实并不需要这份数据,但为了子孙组件能顺利访问数据,都成了数据传递的搬运工。

针对上面两个问题,我们其实可以通过Context得以解决,Context顾名思义就是上下文。就像在一个作用域内我们提前声明了一个变量,后续代码不需要再做引用操作,你都能直接访问它,Context的作用也是如此。

我在整理Context资料的时候发现了一个问题,由于react版本原因,react对于Context的解释也是存在历史变迁的。作为一个初学者,如果你在百度想搜Context用法然后发现了不同的介绍,估计你也会纳闷我到底应该用哪种(或者对于直接上手react-redux的同学可能根本没了解过原生Context的用法),这里我先做个简单的总结,在react版本16.X之前,Context的使用依赖childContextTypes对象,然后手动定义Provider组件,比如在《深入浅出react和Redux》一书中,代码例子的react版本还是15.4.1,所以书中介绍的自然是前面提到的做法。而对于现在的版本比如官方文档中,Context的使用已经不需要手动定义Provider组件了,而是createContext方法手动创建,用法上会人性化很多。

本文还是会站在不同的两个版本,去介绍它们的用法,以达到解决文章开头关于Store引用与传递的问题,当然,如果你已经确定了当前项目的react版本,你可以自由选择对应的版本文档了解其用法。

如果可以,我还是希望有缘看到这篇文章的人能跟着手敲代码,感受其具体的用法,那么本文开始。

贰 ❀ Context 旧版(版本16.X之前)

说在前面,下面的代码仍然基于上一篇文章的例子修改,当然如果没有代码,我尽可能将使用上的细节描述清楚(当然我还是推荐跟着例子来)。如果大家有简单了解过Context,脑海里一定对Provider的单词有所印象,不过对于老版本而言,我们并不能直接引用并使用它,而是需要自己创建,确实非常尴尬。

我们现在src目录下新建一个Provider.js的文件,里面的代码为:

import {Component} from 'react';
import PropTypes from 'prop-types'; class Provider extends Component {
getChildContext() {
// 我们会通过store字段将全局store传递进来
return {
store: this.props.store
};
}
// 渲染Provoder所包裹的子组件内容
render() {
return this.props.children;
}
} Provider.propTypes = {
store: PropTypes.object.isRequired
} Provider.childContextTypes = {
store: PropTypes.object
}; export default Provider;

这段代码有几点需要拧出来说,第一个是关于PropTypes,写过react的同学都知道这是做组件属性的类型检查,比如我一个组件哪些属性是必须提供,哪些是字符串等等。这个东西呢其实也存在一个历史问题....早期版本的react,是可以直接通过引用拿到此对象然后使用,比如:

import { PropTypes } from 'react';

但是在react 15.5之后,此属性被react官方废弃掉了,如果你是版本比较高的react,像上面这样引用会告诉你PropTypesundefied并报错,比如我参考的《深入浅出react和Redux》一书中都是这么用的,因为作者例子的react版本也比较低(15.4.1),而我在写demo的react版本已经是16了,自然用不了,不过也没有关系,咱们可以通过如下方式引用PropTypes

import PropTypes from 'prop-types';

prop-types是一个独立的三方库,因此我们需要提前安装这个包,比如执行命令yarn add prop-types,若你是npm请执行npm i prop-types,这里就不多介绍了,关于prop-types后续也可能会专门写一篇用法的文章。

回到上面的代码中,Provider组件定义的内容其实非常简单,一个getChildContext方法,用于创建子组件的上下文,而上下文中包含的东西其实也就是我们需要使用的store数据,this.props.store怎么来下面的代码会交代。除此之外还有一个render方法,用于渲染Provider包裹的子组件。关于this.props.children这里做个简单补充,比如我们有一个父组件A与一个子组件B,A包裹B,如下:

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
function A(props) {
console.log(props);
return <div>我是父组件{props.children}</div>
}
function B() {
return <div>我是子组件</div>
} ReactDOM.render(
<A><B/></A>,
document.getElementById('root')
);

可以看到我们使用了A包裹了B,在A组件的返回中,我们通过{props.children}成功拿到了包裹的B组件,并将其渲染了出来,通过控制台输出也看的很明显,这里的chindren属性其实就是组件A所包含的组件内容。

我们再过分点,直接修改为如下代码:

ReactDOM.render(
<A>
{
<div>
<div>1</div>
<div>2</div>
</div>
}
</A>,
document.getElementById('root')
);

再看控制台,你会发现通过children属性,我们先访问到了包裹的最外层的div,然后此div的children又是一个数组,因为它又包含了两个div,继续再通过children属性,我们就可以找到数组第一个元素的孩子是一个数字1,这就是react中children的作用,在实际开发中,我们也常会利用此属性达到组件父子组件嵌套的目的。

OK,题外话说完了,再回到上述代码,注意如下这段代码:

Provider.childContextTypes = {
store: PropTypes.object
};

这段代码是必须提供的,不然直接报错,它的类型定义与getChildContext方法中提供的类型相对应,它用于告诉react我现在为子组件提供了一个上下文,上下文中包含的数据有哪些,每个属性是什么类型,关于Provider.js先说到这里。

在上一篇文章的例子中,我们通过index.js文件最终渲染了所有组件,这里我们需要做些修改,具体如下:

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import store from './Store.js';
import Provider from './Provider.js';
import Counter from './Counter.js';
import Summary from './Summary.js';
class ControlPanel extends Component {
render() {
return (
<Provider store={store}>
<div>
<Counter caption="First" />
<Counter caption="Second" />
<hr />
<Summary />
</div>
</Provider>
);
}
} ReactDOM.render(
<ControlPanel />,
document.getElementById('root')
);

我们在此文件中引用了前面定义的Provider组件,同时也引用了全局的Store,然后通过Provider组件将上篇文章中需要渲染的组件进行了包裹,同时通过store字段将引用过来的store作为props传递了下去,这里就对应了Provider.jsgetChildContext方法this.props.store的来源。

上述的修改其实很好理解,我们将Provider作为顶层组件,为需要渲染的所有组件提供了一个共有的上下文,而这个上下文中存在一个store属性,也就是全局的Store,现在子组件们不需要再分别引用Store.js文件了,但这些子组件还需要做一些改变才能支持访问上下文。

Counter组件为例,这里我们说下需要修改的几个点:

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import * as Actions from './Actions.js'; class Counter extends Component {
constructor(props,context) {
super(props,context);
// 初始化组件的state
this.state = this.getOwnState();
} getOwnState = () => {
// 这里的this.props.caption其实就是前面说的First Second
return {
// 这里可以拿到当前的Store数据,并根据key取到对应的初始值
value: this.context.store.getState()[this.props.caption]
};
} onIncrement = () => {
// Actions.increment返回的其实是一个action对象,注意这个函数其实只传递了一个参数,也就是上面提到的First Second类型
this.context.store.dispatch(Actions.increment(this.props.caption));
} onDecrement = () => {
this.context.store.dispatch(Actions.decrement(this.props.caption));
}
// 用于更新state
onChange = () => {
this.setState(this.getOwnState());
} shouldComponentUpdate(nextProps, nextState) {
// 如果state的value变了,通知组件更新
return nextState.value !== this.state.value;
} componentDidMount() {
// 监听Store变化,Store变了我们就让组件的state也跟着变
this.context.store.subscribe(this.onChange);
} componentWillUnmount() {
this.context.store.unsubscribe(this.onChange);
} render() {
const { value } = this.state;
const { caption } = this.props; return (
<div>
<button onClick={this.onIncrement}>+</button>
<button onClick={this.onDecrement}>-</button>
<span>{caption} count: {value}</span>
</div>
);
}
}
// 这里必须定义,不然访问不到Context
Counter.contextTypes = {
store: PropTypes.object
}
export default Counter;

第一点就是我们同样引入了PropTypes,因为在代码最下面,我们必须定义contextTypes的类型,这里与Provider.js中的childContextTypes定义其实是对应的,上下文在创建的时候定义了,子组件在引用上下文时同样得做一个定义声明。

第二点,在constructor中我们知道super方法用于子组件在初始化时继承父组件传递的属性,而这里我们得额外添加一个context,表示将上下文传递进来。

第三点,之前在Counter中我们直接引入了Store.js,因此可以直接访问store的数据以及API方法,但此时我们是通过上下文访问,因此需要对之前所有使用到store的前面添加上this.context,具体可参照上述代码。同理,我们将Summary组件中也做上述三点修改,然后执行yarn start运行项目,你会发现非常完美,项目成功跑起来了。

那么到这里,我们通过旧版的Context做法取代了传统Store引用的做法,达到了只在index.js一处引用统一管理,并可在所有子组件中访问此上下文的目的。

叁 ❀ Context 新版(版本16.X之后)

其实对前面旧版的修改写下来,你会发现这玩意还真不是那么好用,虽说不用每个组件引入Store了吧,咱还得自己手写Provider组件不说,每个用到store的组件还得专门定义contextTypes的类型,实属有点麻烦。没事,我们继续来看新版的Context的用法。当然这次,至少咱们不用手写Provider组件了。

在对于新版本Context资料查阅中,我看到了一句对于Context作用描述比较精准的话,那就是Context能实现组件跨层级的数据传递。比如Props传递一定是逐层的,这可能就会对一些不需要这部分数据的组件造成感染,那么我想越级传递,中间的组件不需要感知这部分数据的存在,Context就是一个不错的渲染。当然回到上文,我们还是可以理解为Context为相关联的组件提供了一个共有上下文,子可见后代也可见,那么就不需要子帮忙传递后代都可以拿着用。因此,除了应对全局Store的数据传递之外,某些部分组件的数据越级传递(比如数据与Store无关,单纯几个层级关系组件之间需要做传递),以及部分子组件,后代组件都需要访问到父组件的部分数据,其实都可以使用此做法达到目的

OK,新版Context的几个核心概念为createContextProviderConsumer,我们一个个说。

叁 ❀ 壹 createContext

createContext顾名思义,创建一个上下文也就是Context对象,它的一般用法为:

const context = React.createContext();

而这个创建出来的context对象中,又包含了ProviderConsumer两个组件,输出如下:

因此在使用时,其实也可以像下面这样直接获取到两个组件:

const {Provider, Consumer} = React.createContext();

createContext可以接受一个参数defaultValue,表示我在创建这个上下文时,就默认定义了一部分的共有的数据,但这个默认数据生效是有条件的,这里引用官方文档的描述:

createContext创建一个 Context 对象。当 React 渲染一个订阅了这个 Context 对象的组件,这个组件会从组件树中离自身最近的 Provider 中读取到当前的 context 值。而如果当前组件所处的组件树中都没有匹配到Provider是,这时候defaultValue就会生效。

怎么理解呢?也就是说我们在父组件创建了一个上下文,但后代组件中只用了Consumer组件,而没有使用Provider对应提供数据,那这时候相当于处于保护措施,我们让defaultValue生效,保证Consumer能拿到默认的数据,免得组件渲染报错了,实属吃低保的行为了。关于这部分的例子,可以参阅React.createContext point of defaultValue?的问题回复,因为这部分知识又涉及到了hookuseContext,简单理解就是父组件中createContext创建上下文,而在子组件中可以使用useContext解析context中的数据,这里我们先不细谈。

叁 ❀ 贰 Provider

顾名思义,与旧版我们定义的Provider作用大致相同,它用于包裹需要享有相同上下文的所有组件,以及为其提供上下文中共有的数据,但需要注意的是,这里的数据传递必须通过value字段,比如:

<Provider value={/*需要传递的共享数据*/}>
/*被包裹的组件们*/
</Provider>

多个Provider可以嵌套使用,但是里层的Provider的value会覆盖掉外层的Provider的value,因此Consumer访问context注定是访问距离自己最近的Provider。除此之外还有一点,当Provider传递的value发生了变化时,Provider内部的所有Consumer组件都会被强制重新渲染,shouldComponentUpdate这玩意都不会限制住它,目的是保证所有消费者组件永远同步感知最新的context变化。

叁 ❀ 叁 Consumer

如名称理解的那样,消费者,也就是消费(使用)Provider传递下来数据的组件。正常情况下,Consumer组件得嵌套在Provider组件之下,但如果如上面所说我们没用Provider组件只用了Consumer组件,那么Consumer组件能访问的上下文就是在createContext中定义的defaultValue

基本API都介绍了,我们来通过这种方式再来改写我们前面的例子。

首先,我们在src目录下新建一个Context.js文件,代码如下:

import React from 'react';

const context = React.createContext();

export default context;

之后,在index.js文件引入context,这里直接再贴上代码:

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import store from './Store.js';
import Counter from './Counter.js';
import Summary from './Summary.js';
import context from './Context.js';
class ControlPanel extends Component {
render() {
return (
//我们使用了Provider包裹子组件,通过value传递store
<context.Provider value={store}>
<div>
<Counter caption="First" />
<Counter caption="Second" />
<hr />
<Summary />
</div>
</context.Provider>
);
}
}
ReactDOM.render(
<ControlPanel />,
document.getElementById('root')
);

同理,我们再次修改Counter组件,还是直接上代码:

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import * as Actions from './Actions.js';
import context from './Context.js';
// const context = React.createContext();
class Counter extends Component {
// static contextType = context;
constructor(props,context) {
super(props,context);
// 初始化组件的state
this.state = this.getOwnState();
} getOwnState = () => {
// 这里的this.props.caption其实就是前面说的First Second
return {
// 这里可以拿到当前的Store数据,并根据key取到对应的初始值
value: this.context.getState()[this.props.caption]
};
} onIncrement = () => {
// Actions.increment返回的其实是一个action对象,注意这个函数其实只传递了一个参数,也就是上面提到的First Second类型
this.context.dispatch(Actions.increment(this.props.caption));
} onDecrement = () => {
this.context.dispatch(Actions.decrement(this.props.caption));
}
// 用于更新state
onChange = () => {
this.setState(this.getOwnState());
} shouldComponentUpdate(nextProps, nextState) {
// 如果state的value变了,通知组件更新
return nextState.value !== this.state.value;
} componentDidMount() {
// 监听Store变化,Store变了我们就让组件的state也跟着变
this.context.subscribe(this.onChange);
} componentWillUnmount() {
this.context.unsubscribe(this.onChange);
} render() {
const { value } = this.state;
const { caption } = this.props; return (
<div>
<button onClick={this.onIncrement}>+</button>
<button onClick={this.onDecrement}>-</button>
<span>{caption} count: {value}</span>
</div>
);
}
}
Counter.contextType = context;
export default Counter;

因为我们需要在Counter组件使用context,因此也需要引入context。之后,我们通过Counter.contextType = context;为当前组件绑定context对象,同理,在constructor中还是得初始化context,之后在组件任意地方,我们都可以通过this.context访问到传递进来的store,注意啊,这里的this.context已经等同于store本身了,所以代码中是this.context.subscribe直接调用store上的API。你可能有点不习惯,还是希望this.context.store去访问,那就像如下方式这样传递,比如假设我们需要给Provider传递多个值:

class ControlPanel extends Component {
render() {
const value = {
store,
name:1
};
return (
<context.Provider value={value}>
<div>
<Counter caption="First" />
<Counter caption="Second" />
<hr />
<Summary />
</div>
</context.Provider>
);
}
}

我们再去Counter断点this,你就发现这就是你预期的样子了

其实可以发现,新版的context在使用上与旧版还是有些类似的,在使用context的地方同样得为组件做contextType的定义以及context的初始化,我们同理去修改掉Summary中的代码,执行运行项目的命令,你会发现也能完美跑起来,那么到这里,我们又通过新版Context的做法修改了例子。

当然到这里我们还没用到Consumer,那么接下来我们再单独用一个例子,再次结合把ProviderConsumer用一用。接下来我们定义ABC三个组件,A嵌套B,B又嵌套C,直接修改index.js中的代码:

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import context from './Context.js';
class A extends Component {
render() {
const name = '听风是风';
return (
<context.Provider value={name}>
<div>{`我是A组件,我传递了${name}`}</div>
{/* 注意,这里我们并没有将name作为props传递下去 */}
<B />
</context.Provider>
)
}
}
function B() {
return (
<context.Consumer>
{
(name) => {
console.log(name);
return (
<div>
{`我是B组件,我接受了${name}`}
<C />
</div>
)
}
} </context.Consumer>
)
}
function C() {
return (
<context.Consumer>
{
(name)=>{
return (
<div>
{`我是C组件,我接受了${name}`}
</div>
)
}
}
</context.Consumer>
)
}
ReactDOM.render(
<A />,
document.getElementById('root')
);

可以看到,在子组件需要使用context的地方,我们通过context.Consumer将其包裹,而context.Consumer之间接受一个函数,此函数接受一个参数(参数随便你叫什么),此参数就是Provider的映射,比如我们上面传递的是一个字符串,注意,只有一层花括号进行了包裹,所以函数形参name直接就是所传递值的映射。

那假设我们传递了多个参数呢?还是一样,我们稍作修改,这里只贴上修改的部分,并在子组件函数中尝试打印:

class A extends Component {
render() {
const name = '听风是风';
const age = '28';
return (
<context.Provider value={{name,age}}>
<div>{`我是A组件,我传递了${name}`}</div>
{/* 注意,这里我们并没有将name作为props传递下去 */}
<B />
</context.Provider>
)
}
} function B() {
return (
<context.Consumer>
{
// 参数其实可以随便你取名
(aaa) => {
console.log(aaa);
return (
<div>
{`我是B组件,我接受了${aaa.name}`}
<C />
</div>
)
}
} </context.Consumer>
)
}

当然实际开发中,我们不会推荐这样传递多个参数,因为上述代码中value={{name,age}}部分,代码每次执行{name,age}可以理解为每次都是一个全新的对象,由于对象引用不同这会导致react认为value每次都在发生变化,从而引发子组件全部更新,推荐的做法是使用一个变量去声明一个对象包含这两个变量,比如:

// 这里只贴主要修改部分
const user = {
name:'听风是风',
age:28
}
return (
<context.Provider value={user}>
<div>{`我是A组件,我传递了${user.name}`}</div>
{/* 注意,这里我们并没有将name作为props传递下去 */}
<B />
</context.Provider>
) <context.Consumer>
{
(user) => {
return (
<div>
{`我是B组件,我接受了${user.name}`}
<C />
</div>
)
}
} </context.Consumer>

那么到这里,我们其实展示了两种在子组件中访问context的方式,第一种是为组件绑定contextType,第二种就是使用Consumer,那么我们直接将C组件修改成如下的方式:

class C extends Component {
constructor(props, context) {
super(props, context)
}
render() {
return (
<div>
{`我是C组件,我接受了${this.context}`}
</div>
)
}
}
C.contextType = context;

可以看到我们没有借用Consumer,而是借用组件contextType绑定后,同样成功访问到了父组件传递的数据。

那么到这里,我们介绍了react中新旧context的基本用法,旧版context需要自定义Provider,并结合getChildContext定义为子组件传递的数据。而新版context在使用上相对友好了不少,我们可以通过createContext创建一个context实例,并可以直接使用Provider提供数据,使用Consumer消费数据。通过文中新旧例子对比,其实两者在使用上存在不少相同点。

在下一篇文章中,我们来了解react-redux基本用法,其实本篇文章与上一篇文章属于react-redux的铺垫篇,在了解了react原生的概念后,我想在理解三方封装时应该会容易很多,那么到这里本文结束。

参考

深入浅出react和Redux 第三章组件context部分

React Context(上下文) 作用和使用 看完不懂 你打我

React系列——React Context

react官网文档Context

React中Context的使用

React context基本用法

从零开始的react入门教程(九),react context上下文详解,可能有点啰嗦,但很想让你懂的更多相关文章

  1. Python学习入门教程,字符串函数扩充详解

    因有用户反映,在基础文章对字符串函数的讲解太过少,故写一篇文章详细讲解一下常用字符串函数.本文章是对:程序员带你十天快速入门Python,玩转电脑软件开发(三)中字符串函数的详解与扩充. 如果您想学习 ...

  2. react 入门教程 阮一峰老师真的是榜样

    -  转自阮一峰老师博客 React 入门实例教程   作者: 阮一峰 日期: 2015年3月31日 现在最热门的前端框架,毫无疑问是 React . 上周,基于 React 的 React Nati ...

  3. React入门教程(二)

    前言 距离上次我写 React 入门教程已经快2个月了,年头年尾总是比较忙哈,在React 入门教程(一)我大概介绍了 React 的使用和一些注意事项,这次让我们来继续学习 React 一. Rea ...

  4. React入门教程1---初见面

    React入门教程1---初见面:https://blog.csdn.net/solar_lan/article/details/82799248 React 教程 React 是一个用于构建用户界面 ...

  5. 无废话ExtJs 入门教程九[数字字段:NumberField、隐藏字段Hidden、日期字段:DataFiedl]

    无废话ExtJs 入门教程九[数字字段:NumberField.隐藏字段Hidden.日期字段:DataFiedl] extjs技术交流,欢迎加群(201926085) 继上第六节内容,我们在表单里加 ...

  6. RabbitMQ入门教程(九):首部交换机Headers

    原文:RabbitMQ入门教程(九):首部交换机Headers 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog ...

  7. Android 颜色渲染(九) PorterDuff及Xfermode详解

    版权声明:本文为博主原创文章,未经博主允许不得转载. Android 颜色渲染(九)  PorterDuff及Xfermode详解 之前已经讲过了除ComposeShader之外Shader的全部子类 ...

  8. Asp.Net MVC3 简单入门第一季(三)详解Controller之Filter

    前言 前面两篇写的比较简单,刚开始写这个系列的时候我面向的对象是刚开始接触Asp.Net MVC的朋友,所以写的尽量简单.所以写的没多少技术含量.把这些技术总结出来,然后一简单的方式让更多的人很好的接 ...

  9. ASP.NET MVC 5 学习教程:生成的代码详解

    原文 ASP.NET MVC 5 学习教程:生成的代码详解 起飞网 ASP.NET MVC 5 学习教程目录: 添加控制器 添加视图 修改视图和布局页 控制器传递数据给视图 添加模型 创建连接字符串 ...

  10. java加密算法入门(三)-非对称加密详解

    1.简单介绍 这几天一直在看非对称的加密,相比之前的两篇内容,这次看了两倍多的时间还云里雾里的,所以这篇文章相对之前的两篇,概念性的东西多了些,另外是代码的每一步我都做了介绍,方便自己以后翻阅,也方便 ...

随机推荐

  1. 使用docker compose 编排微服务发布

    本文为博主原创,未经允许不得转载: 目录: 1. compose 简介 2. compose 安装 3. 编写 docker-compose.yml 实现微服务发布 4. docker-compose ...

  2. 软考下午科目——第三章——UML分析与设计

    UML分析与设计 大纲要求: 学会面向对象的分析与设计,掌握UML描述方法 UML基础知识 面向对象的分析与设计 面向对象方法是一种运用对象.类.继承.封装.聚合.关联.消息.多态性等概念来构造系统的 ...

  3. 百度网盘(百度云)SVIP超级会员共享账号每日更新(2023.11.26)

    一.百度网盘SVIP超级会员共享账号 可能很多人不懂这个共享账号是什么意思,小编在这里给大家做一下解答. 我们多知道百度网盘很大的用处就是类似U盘,不同的人把文件上传到百度网盘,别人可以直接下载,避免 ...

  4. [转帖]Linux内存之Cache

    一. Linux内存之Cache 1.1.Cache 1.1.1.什么是Cache? Cache存储器,是位于CPU和主存储器DRAM之间的一块高速缓冲存储器,规模较小,但是速度很快,通常由SRAM( ...

  5. Mysql8.0.32 union all创建视图无法使用中文模糊查询的坑

    Mysql8.0.32 union all创建视图无法使用中文模糊查询的坑 摘要 本周研发同事反馈现场有一个问题. 客户使用mysql的数据库(Windows平台) 然后在多表union all 创建 ...

  6. [转帖]【性能】中断绑定和查看|irqbalance 中断负载均衡|CPU瓶颈

    常用命令 ``` # 查看当前运行情况 service irqbalance status # 终止服务 service irqbalance stop 取消开机启动: chkconfig irqba ...

  7. 时间片 线程切换 指令周期 流水线 TPS的初步了解

    时间片 线程切换 指令周期 流水线 TPS的初步了解 情况说明 Redis 单线程提供服务, 可以支撑十万级别的TPS 通过以个非常简单的测试 redis-benchmark -c 50 -n 500 ...

  8. CentOS firewall简单总结

    CentOS firewall简单总结 简介 防火墙是安全的重要道防线. 硬件防火墙一般部署再内网的边界区域.作为最外层的防护. 但是一般硬件的防火墙会比较宽松. 不然会导致很多业务不可用 软件防火墙 ...

  9. CentOS8 设置开机自动登录账户的方法

    CentOS8 设置开机自动登录账户的方法 修改/etc/gdm/custom.conf文件, 并且添加内容即可. vim /etc/gdm/custom.conf # 在配置节下添加如下内容. [d ...

  10. 【发现一个问题】使用 fastcgo 导致额外的 `runtime._System` 调用的消耗

    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 为了避免 cgo 调用浪费太多资源,因此使用了 fastc ...