react-redux(由浅到深)

news2024/11/15 12:53:58

文章目录

    • 1. redux
      • 1.1 概述与使用原则
      • 1.2工作流程
        • 1.2.1 三个核心
      • 1.3 store
      • 1.4 action
      • 1.5 reducer
        • 1.5.1 合并reducers
      • 1.6 dispatch getState 及状态更新
    • 2. react-redux
      • 2.1 基本特征
      • 2.2 connect()、mapStateToProps
      • 2.3 mapDispatchToProps
      • 2.4Provider
      • 2.5. 中间件,combineReducers函数,redux-devtools
    • 3. Redux Toolkit
      • 3. 1 基本特征与API
      • 3.2 createSlice
      • 3.3 store 创建
      • 3.4 Provide ,connect
      • 3.5 Redux Toolkit的异步操作
    • 4. hooks,useSelector、useDispatch

图解
在这里插入图片描述

1. redux

npm install redux --save

1.1 概述与使用原则

  • 是一个专门用来做状态管理的js库(不是react插件)
  • 作用:集中式管理react应用中的多个组件共享的状态
  • 使用:
    • 某个组件的状态,需要让其他组件可以随时拿到(共享)
    • 一个组件需要改变另一个组件的状态(通信)

1.2工作流程

redux工作流程图如下:
在这里插入图片描述

1.2.1 三个核心

  • action
    • 动作的对象
    • 包含两个属性
      • type:属性标识,值为字符串,唯一,必要属性
      • data:数据属性,值任意类型,可选属性
      • 例子 {type:'CHANGE_NAME', data: {name: 'why'}}
  • reducer
    • 用于初始化、加工状态
    • 加工时,根据旧的state和action,产生新的state的纯函数
    • 例子 if (type === 'CHANGE_NAME') {return { ...state, name }}

store

  • stateactionreducer联系在一起的对象
  • 加工时,根据旧的state和action,产生新的state的纯函数

1.3 store

  • 整个文件以modules划分
│  └─ store
│     ├─ actions // actions,文件夹内以模块区分
│     │  ├─ count.js
│     │  └─ person.js
│     ├─ constants.js // action type唯一标识常量
│     ├─ index.js // 入口文件
│     └─ reducer // reducer,文件夹内以模块区分
│        ├─ conut.js
│        ├─ index.js // reducer统一暴露文件,合并reducers
│        └─ persons.js
  • 引入createStore,专门用于创建redux中最为核心的store对象,而redux-thunk、applyMiddleware用于支持异步action,

npm i redux-thunk

// src/store/index.js
import { createStore, applyMiddleware } from "redux";
// 用于支持异步action
import thunk from "redux-thunk";
import reducers from "./reducers";
export default createStore(reducers, applyMiddleware(thunk));

1.4 action

  • 定义action对象中type类型的常量值
// src/store/constants.js
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
  • 创建action,action返回对象 ,异步action返回函数 可用于发送网络请求,执行setTimeout等,
// src/store/actions/count.js
import { INCREMENT, DECREMENT } from "../constants";
// 普通action的值为object `{type: INCREMENT, data }`
export const increment = data => ({ type: INCREMENT, data });
export const decrement = data => ({ type: DECREMENT, data });
export const incrementAsync = (data) => {
  return (dispatch) => {
    setTimeout(() => {
      dispatch(increment(data));
    }, 500);
  };
};
  • 异步action
    • 延迟的动作不想交给组件本身,想交给action
    • 执行异步方法对状态进行操作,但是具体的数据需要靠异步任务返回

1.5 reducer

  • reducer函数会接到两个参数,分别为:之前的状态(state),动作对象(action)
  • 从action对象中获取typedata
  • 根据type决定如何加工数据
  • reducer没有初始化值时为undefined 因此我们可以设置初始值 initialState
import {INCREMENT, DECREMENT} from '../constants'
// 初始化状态
const initialState= 0;

export default function count(state = initialState, action) {
  const { type, data } = action;
  switch (type) {
    case INCREMENT:
      return state + data;
    case DECREMENT:
      return state - data;
    default:
      return state;
  }
}

注意

  • state只读

    • 唯一修改State的方法一定是触发action,不要试图在其他地方通过任何的方式来修改State:这样可以保证所有的修改都被集中化处理,并且按照严格的顺序来执行,所以不需要担心race condition(竟态)的问题;
  • 使用纯函数来执行修改

    • 通过reducer将 旧state和 actions联系在一起,并且返回一个新的State:
    • 随着应用程序的复杂度增加,我们可以将reducer拆分成多个小的reducers,分别操作;
    • 但是所有的reducer都应该是纯函数,不能产生任何的副作用

1.5.1 合并reducers

通过combineReducers合并,接收的参数是一个对象,对象的key值与getState()得到的对象的key一致

// src/store/reducers/index.js
import { combineReducers } from "redux";
import count from "./conut";
import persons from "./persons";
export default combineReducers({
  count,
  persons,
});

1.6 dispatch getState 及状态更新

  • 组件通过getState()拿store的数据
  • dispatch触发action
  • subscribe() 完成视图更新
import store from "../../store";
import { increment } from "../../store/action/count";
//redux内部不支持自动更新,需要通过subscribeAPI监听redux中状态变化,只有变化,就需要重新调用render
 componentDidMount() {
    store.subscribe(() => {
      this.forceUpdate();
    });
}
  clickIncrement = () => {
    store.dispatch(increment(+1));
  };
 render() {
    return (
      <div>
        <h1>当前求和为: {store.getState()}</h1>
        ...
        <button onClick={this.clickIncrement}>+</button>
      </div>  
      )
 }

2. react-redux

2.1 基本特征

  • redux需要监听store变化更新视图,利用store.subscribe(() => { this.forceUpdate(); });react-redux不需要监听
  • react-redux将组件分为UI组件容器组件;redux的操作都在容器组件中,
  • 单一职责原则;通过connect(mapStateToProps, mapDispatchToProps)(UI)连接容器组件与UI组件;redux没有区分
  • UI组件负责UI的呈现,容器组件负责管理数据和逻辑,如果一个组件既有UI又有业务逻辑,将它拆分成下面的结构:外面是一个容器组件,里面包了一个UI 组件。前者负责与外部的通信,将数据传给后者,由后者渲染出视图
    在这里插入图片描述

2.2 connect()、mapStateToProps

  • React-Redux提供connect方法,用于从UI组件生成容器组件
  • 下面代码中,CountUIUI组件,利用connect最后导出的是容器组件
  • 为了定义业务逻辑,需要给出下面两方面的信息:

输入逻辑:外部的数据(即state对象)如何转换为 UI 组件的参数
输出逻辑:用户发出的动作如何变为 Action 对象,从 UI组件传出去

connect方法接受两个参数:mapStateToPropsmapDispatchToProps。它们定义了 UI 组件的业务逻辑。前者负责输入逻辑,即将state映射到 UI 组件的参数(props),后者负责输出逻辑,即将用户对 UI 组件的操作映射成 Action
mapStateToProps 接收 state 参数,mapDispatchToProps 接收 dispatch 参数

// 容器组件
import { connect } from "react-redux";
import CountUI from "../../components/count";
import {
  createIncrementAction,
  createDecrementAction,
  createIncrementAsyncAction,
} from "../../redux/count_action";

const mapStateToProps = (state) => ({ count: state });

const mapDispatchToProps = (dispatch) => ({
  increment: (number) => {
    dispatch(createIncrementAction(number));
  },
  incrementAsync: (number) => {
    dispatch(createIncrementAsyncAction(number, 500));
  },
  decrement: (number) => {
    dispatch(createDecrementAction(number));
  },
});
export default connect(mapStateToProps, mapDispatchToProps)(CountUI);
// UI组件
import React, { Component } from "react";

export default class CountUI extends Component {
  // 加法
  increment = () => {
    const { value } = this.selectNumber;
    this.props.increment(value * 1);
  };

  // 减法
  decrement = () => {
    const { value } = this.selectNumber;
    this.props.decrement(value * 1);
  };

  // 奇数加
  incrementIfOdd = () => {
    if (this.props.count % 2 === 1) {
      const { value } = this.selectNumber;
      this.props.increment(value * 1);
    }
  };

  // 异步加
  incrementAsync = () => {
    const { value } = this.selectNumber;
    this.props.increment(value * 1);
  };

  render() {
    return (
      <div>
        <h1>当前求和为: {this.props.count}</h1>
        ...
      </div>
    );
  }
}

2.3 mapDispatchToProps

mapDispatchToPropsconnect函数的第二个参数,用来建立 UI 组件的参数到store.dispatch方法的映射。也就是说,它定义了哪些用户的操作应该当作 Action,传给 Store
它可以是一个函数,也可以是一个对象

  • 如果mapDispatchToProps是一个函数
/ 容器组件
const mapDispatchToProps = (dispatch) => ({
  increment: (number) => {
    dispatch(createIncrementAction(number));
  },
  incrementAsync: (number) => {
    dispatch(createIncrementAsyncAction(number));
  },
  decrement: (number) => {
    dispatch(createDecrementAction(number));
  },
});

// mapDispatchToProps的一般写法,返回function
export default connect(mapStateToProps, mapDispatchToProps)(CountUI);
  • 如果mapDispatchToProps是一个对象

    键值是一个函数,Action creator ,返回的 Action 会由 Redux 自动发出

// mapDispatchToProps的简写,返回object
export default connect(mapStateToProps, {
  increment: createIncrementAction,
  incrementAsync: createIncrementAsyncAction,
  decrement: createDecrementAction,
})(CountUI);

2.4Provider

connect方法生成容器组件以后,需要让容器组件拿到state对象,才能生成 UI 组件的参数。
一种解决方法是将state对象作为参数,传入容器组件。但是,这样做比较麻烦,尤其是容器组件可能在很深的层级,一级级将state传下去就很麻烦。

// src/App.js
import React, { Component } from "react";
import Count from "./container/count";
import store from "./redux/store";

export default class App extends Component {
  render() {
    return <Count store={store} />;
  }
}
  • React-Redux 提供Provider组件,可以让容器组件拿到state
  • Provider在根组件外面包了一层,这样一来,App的所有子组件就默认都可以拿到state了
  • 它的原理是React组件的context属性
  • 使原来整个应用成为Provider的子组件 接收Redux的store作为props,通过context对象传递给子孙组件上的connect
// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { Provider } from "react-redux"
import store from "./store"

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  // <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  // </React.StrictMode>
);

2.5. 中间件,combineReducers函数,redux-devtools

  • 中间件

    • 中间件的目的是在dispatchaction和最终达到的reducer之间,扩展一些自己的代码;
    • 比如日志记录调用异步接口添加代码调试功能等等;
    • redux-thunkapplyMiddleware用于支持异步action,
  • combineReducers函数

    • 它也是将我们传入的reducers合并到一个对象中,最终返回一个combination的函数(相当于我们之前的reducer函数了);
    • 在执行combination函数的过程中,它会通过判断前后返回的数据是否相同来决定返回之前的state还是新的state;
    • 新的state会触发订阅者发生对应的刷新,而旧的state可以有效的组织订阅者发生刷新;
  • redux-devtools

    • 利用这个工具,我们可以知道每次状态是如何被修改的修改前后的状态变化
import { applyMiddleware, compose, createStore,combineReducers  } from 'redux';
import thunk from 'redux-thunk';
import count from "./conut";
import persons from "./persons";
const reducer= combineReducers({
  count,
  persons,
});
//创建store 传递reducer
// redux-devtools
// trace 开启
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ trace: true }) || compose;
const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)))

3. Redux Toolkit

3. 1 基本特征与API

  • Redux Toolkit 也被称为RTK

npm install @reduxjs/toolkit react-redux

  • Redux Toolkit的核心API主要是如下几个:
    • configureStore:包装createStore以提供简化的配置选项和良好的默认值。它可以自动组合你的 slice reducer,添加你提供的任何 Redux 中间件,redux-thunk默认包含,并启用 Redux DevTools Extension。
    • createSlice:接受reducer函数的对象、切片名称和初始状态值,并自动生成切片reducer,并带有相应的actions。
    • createAsyncThunk: 接受一个动作类型字符串和一个返回承诺的函数,并生成一个pending/fulfilled/rejected基于该承诺分派动作类型的 thunk

3.2 createSlice

通过createSlice创建一个slice ,createSlice主要包含如下几个参数:

  • name:用户标记slice的名词, 在之后的redux-devtool中会显示对应的名词;
  • initialState:初始化值,第一次初始化时的值;
  • reducers:相当于之前的reducer函数
    • 对象类型,并且可以添加很多的函数;
    • 函数类似于redux原来reducer中的一个case语句;
    • 函数的参数:state和action 调用这个action时传递的action参数
  • extraReducers 监听异步结果

createSlice返回值是一个对象,包含所有的actions;

import { createSlice } from '@reduxjs/toolkit';
const homeReducer = createSlice({
	name: 'home',
	initialState: {
		banners: [],
		recommends: []
	},
	reducers: {
		changeRecommendActios(state, { paylaod }) { 
			state.recommends=paylaod
		},
		changeBannerActions(state, { payload }) { 
			state.banners=payload
		}
	}
})

export const { changeBannerActions, changeRecommendActios } = homeReducer.actions
export default homeReducer.reducer

3.3 store 创建

  • configureStore用于创建store对象,常见参数如下:
    • reducer,将slice中的reducer可以组成一个对象传入此处;
    • middleware:可以使用参数,传入其他的中间件
    • devTools:是否配置devTools工具,默认为true;
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './modules/Counter';
import homeReducer from './modules/Home';
const store = configureStore({
	reducer: {
		//  这里做分包
		counter: counterReducer,
		home: homeReducer
	}
})
export default store

3.4 Provide ,connect

  • Provide 还是需要提供store
import React from "react";
import ReactDOM from "react-dom/client";
import { Provider } from 'react-redux';
import App from "./App";
import store from './store';
const root = ReactDOM.createRoot(document.getElementById("root"));
//  1. react-redux使用 第一步提供全局store
root.render(
	//  严格模式 render执行两次
	<Provider store={store} >
		<App />
 </Provider>
);

3.5 Redux Toolkit的异步操作

Redux Toolkit默认已经给我们继承了Thunk相关的功能:createAsyncThunk

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import axios from 'axios';
export const fetachHomeActions = createAsyncThunk('home/multidata', async (payload, extraInfo) => {
	const res = await axios.get("http://123.207.32.32:8000/home/multidata")
	return res.data
})
  • 当createAsyncThunk创建出来的action被dispatch时,会存在三种状态
    • pending:action被发出,但是还没有最终的结果;
    • fulfilled:获取到最终的结果(有返回值的结果);
    • rejected:执行过程中有错误或者抛出了异常;
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import axios from 'axios';
export const fetachHomeActions = createAsyncThunk('home/multidata', async (payload, extraInfo) => {
	const res = await axios.get("http://123.207.32.32:8000/home/multidata")
	return res.data
})
const homeReducer = createSlice({
	name: 'home',
	initialState: {
		banners: [],
		recommends: []
	},
	reducers: {
		changeRecommendActios(state, { paylaod }) {
			state.recommends = paylaod
		},
		changeBannerActions(
			state, { payload }
		) {
			state.banners = payload
		}
	},
	// 异步操作(三种状态)
	extraReducers: {
		[fetachHomeActions.pending](state, action) {
			console.log(action);
		},
		[fetachHomeActions.fulfilled](state, { payload }) {
			state.banners=payload.data.banner.list
		},
		[fetachHomeActions.rejected](sate, action) {
		}
	}
})

export const { changeBannerActions, changeRecommendActios } = homeReducer.actions
export default homeReducer.reducer

链式调用

// 异步操作(三种状态)(链式调用的形式)
	extraReducers: (builder) => {
		builder.addCase(fetachHomeActions.pending, (state, action) => {
			console.log("fetachHomeActions pending")
		}).addCase(fetachHomeActions.fulfilled, (state, { payload }) => {
			state.banners = payload.data.banner.list
			state.recommends = payload.data.recommend.list
		})
	}

4. hooks,useSelector、useDispatch

  • createSlice 创建reducer
import { createSlice } from '@reduxjs/toolkit';
const initialState = {
  value: 0,
};
export const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    increment: (state) => {
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },
  },
})
  • 使用useSelector访问/使用state
const {counter} = useSelector((state) => state.counter.counter);

// 优化
// 1. memo包裹只有只有props改变才会重新渲染
  // 2.第二个参数shallowEqual 进行浅层比较 (就是reducer中返回完全相同的对象  才不进行重新渲染)
  // shallowEqual 解决使用相同的参数调用时,useSelector返回不同的结果。这可能导致不必要的重新渲染。
const App = memo((props) => {
  const { counter } = useSelector((state) => ({
    counte: state.counter.counter
  }),shallowEqual)
  return (
    <div>
      <h1>{counter}</h1>
    </div>
  )
})
  • 使用useDispatch变更state
    useDispatch接收的是你在createSlice中定义的reducers里的action,比如把increment传给useDispatch即可给state加1。
import {useSelector, useDispatch } from 'react-redux';
import {
  decrement,
  increment,
} from './counterSlice';
export function Counter() {
 const count = useSelector((state) => state.counter.value);
 const dispatch = useDispatch();
  return (
    <div>
      <div>
        <button
          aria-label="Decrement value"
          onClick={() => dispatch(decrement())}
        >
          -
        </button>
        <span>{count}</span>
        <button
          aria-label="Increment value"
          onClick={() => dispatch(increment())}
        >
          +
        </button>
      </div>
    </div>
  );
}

参考文章:jjjona0215大神

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

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

相关文章

【动手学习深度学习--逐行代码解析合集】04softmax回归的从零开始实现

【动手学习深度学习】逐行代码解析合集 04softmax回归的从零开始实现 视频链接&#xff1a;动手学习深度学习–softmax回归的从零开始实现 课程主页&#xff1a;https://courses.d2l.ai/zh-v2/ 教材&#xff1a;https://zh-v2.d2l.ai/ 1、 softmax网络架构 2、 softmax运算 3、…

实验三:运算类编程实验

实验目的 阐明本实验的目的。 一实验目的掌握学精变C6应) 乘汉运第《结购 3位)江程产设计方法穿握双精度[3位)加法运算乡饰程产设计方法穿握双精度园) 朱讼运算 [结果为64位)汇编往广设计方讯 实验要求 说明实现本实验需要掌握的知识及本实验需要的实验环境 、实强要求 了解简单…

20+个小而精的Python实战案例(附源码和数据)

公众号&#xff1a;尤而小屋作者&#xff1a;Peter编辑&#xff1a;Peter 大家好&#xff0c;我是Peter~ 最近小编认真整理了20个基于python的实战案例&#xff0c;主要包含&#xff1a;数据分析、可视化、机器学习/深度学习、时序预测等&#xff0c;案例的主要特点&#xff1…

spring boot security验证码登录示例

前言 在spring boot security自定义认证一文&#xff0c;基本给出了一个完整的自定义的用户登录认证的示例&#xff0c;但是未涉及到验证的使用&#xff0c;本文介绍登录的时候如何使用验证码。 本文介绍一个验证码生成工具&#xff0c;比较老的一个库了&#xff0c;仅作demo…

rust warp框架教程1-helloworld

warp框架简介 warp is a super-easy, composable, web server framework for warp speeds. warp建立在hyper之上&#xff0c;因此&#xff0c;warp天生支持异步&#xff0c;HTTP/2&#xff0c;以及“正确的HTTP实现”。 warp的强大之处在于其提供的filter系统&#xff0c;它…

软件设计模式与体系结构-设计模式-生成模式单例模式

目录 二、生成器模式1. 生成者模式概念实例一&#xff1a;房屋选购系统题目时序图类图 优缺点适用场景 2. 生成器模式与抽象工厂模式3. 课程作业*** 三、单例模式1. 单例模式要点&#xff1a;基本思路实例一&#xff1a;互联网连接问题 2. 多线程情况3. 优缺点4. 适用场景5. 课…

leetcode 88.合并两个有序数组

⭐️ 题目描述 &#x1f31f; leetcode链接&#xff1a;合并两个有序数组 ⭕️ 代码&#xff1a; /*思路&#xff1a;双指针问题1.从前往后拷贝依次比较两个数组元素的较小值&#xff0c;较小值先拷贝- 问题&#xff1a;从前拷贝会造成覆盖(有问题)2.从后往前拷贝依次比较两个…

SpringBoot(五)SpringBoot事务

在实际开发项目时&#xff0c;程序并不是总会按照正常的流程去执行&#xff0c;有时候线上可能出现一些无法预知的问题&#xff0c;任何一步操作都有可能发生异常&#xff0c;异常则会导致后续的操作无法完成。此时由于业务逻辑并未正确的完成&#xff0c;所以在之前操作过数据…

单臂路由实现不同VLAN之间数据转发

实验环境&#xff1a; 思科模拟器&#xff0c;Cisco Packet Tracer 实验拓扑&#xff1a; 实验配置&#xff1a; &#xff08;1&#xff09;PC配置 IP地址子网掩码网关PC1192.168.10.1255.255.255.0192.168.10.254PC2192.168.10.2255.255.255.0192.168.10.254PC3192.168.20…

串口通讯监控方法

当我们调试硬件的时候&#xff0c;发现串口数据异常&#xff0c;用示波器和逻辑分析仪的话会比较麻烦&#xff0c;此时可以并一个监控串口&#xff0c;如下图所示 232串口&#xff0c;我们是不能直接并一个串口上去的&#xff1b;但是我们的监控串口&#xff0c;可以只接一根R…

【玩转循环】探索Python中的无限可能性

前言 循环可能是每个编程语言中使用比较多的语法了&#xff0c;如果能合理利用好循环&#xff0c;就会出现意想不到的结果&#xff0c;大大地减少代码量&#xff0c;让机器做那些简单枯燥的循环过程&#xff0c;今天我将为大家分享 python 中的循环语法使用。&#x1f697;&am…

数据结构--栈的链式存储

数据结构–栈的链式存储 推荐使用不带头结点的单链表 \color{green}推荐使用不带头结点的单链表 推荐使用不带头结点的单链表 typedef struct LNode {ElemType data;struct LNode* next; } LNode, *LinkList;bool InitList(LinkList &L) {L->next NULL; }后插操作&…

python网络编程(二)模拟ssh远程执行命令

1、项目需求&#xff1a; 要实现一个像ssh远程连接工具一样&#xff0c;在终端输入命令&#xff0c;返回对应的结果。 比如window的dos命令&#xff1a; dir &#xff1a;查看目录下的文件 ipconfig : 查看网卡信息 tasklist : 查看进程列表 linux的命令&#xff1a; ls : 查看…

Jenkins与CI/CD

简介 CI&#xff08;持续集成&#xff09; Continuous Integration是一种软件开发实践&#xff0c;即团队开发成员经常集成他们的工作&#xff0c;通常每个成员每天至少集成一次&#xff0c;也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建&#xff08;包括编…

Debian 环境使用 docker compose 部署 sentry

Debian 环境使用 docker compose 部署 sentry Sentry 简介什么是 Sentry &#xff1f;Sentry 开发语言及支持的 SDKSentry 功能架构 前置准备条件规格配置说明Dcoker Desktop 安装WSL2/Debian11 环境准备 Sentry 安装步骤docker 部署 sentry 步骤演示过程说明 总结 Sentry 简介…

python机器学习在气象模式订正、短临预报、气候预测等场景的应用

基于机器学习的天河机场物流预测研究 全球经济快速增长的形势下,八大区域性枢纽之一的武汉天河机场的物流需求也在攀升。文章针对天河机场的货邮吞吐量,运用机器学习中的线性回归模型通过Python对其进行需求预测,并用二次指数平滑法与之对比,在平均绝对百分误差比较下得出机器…

需求分析引言:架构漫谈(四)性能专题

前文介绍了非功能性需求里的可靠性和可用性&#xff0c; 本文对非功能性需求里的性能&#xff0c;进行一些详细的说明&#xff0c;和如何度量系统的性能问题。 1、概念 性能通常是指一个软件系统的处理能力和速度&#xff0c;一般通过 延迟 和 吞吐量 这两个指标进行度量。 不…

分布式软件架构——域名解析系统

透明多级分流系统的设计原则 用户在使用信息系统的过程中&#xff0c;请求首先是从浏览器出发&#xff0c;在DNS的指引下找到系统的入口&#xff0c;然后经过了网关、负载均衡器、缓存、服务集群等一系列设施&#xff0c;最后接触到了系统末端存储于数据库服务器中的信息&…

云计算——容器

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​ 目录 前言 一.容器简介 二.主流容器技术 1.docker &#xff08;1&#xff09;容器的组…

HTML5+ Runtime提示

使用的环境 vue-cli框架&#xff0c;Andriod调试、云打包都会出现该弹框 1.我遇到的问题 上述弹框提示&#xff0c;HBuilderX3.8.2 &#xff0c; 手机SDK版本是3.8.4&#xff0c;不匹配 解决目的&#xff1a;需要让两个版本匹配 2. 点击“查看详情”&#xff0c;查看原因 …