flash素材网站/sem推广案例
React 服务器端渲染概念回顾
什么是客户端渲染CSR(Client Side Rendering)
服务器端只返回json数据,Data和Html的拼接在客户端进行(渲染)。
什么是服务器端渲染SSR(Server Side Rendering)
服务器端返回数据拼接过后的HTML,Data和Html的拼接在服务器端进行(渲染)。
使用react实现的应用都是单页应用(Singe Page Application),都属于是客户端渲染。
为什么要实现服务器端渲染,SPA的服务器端渲染旨在解决哪些问题呢。
客户端首页渲染时间长,大部分时间处于页面外链的加载等待状态,用户体验差。
页面结构是空的,不利于网站的SEO
SSR同构,同构指的是代码复用,即实现客户端和服务器端最大程度的的代码复用。
原生实现
项目结构
react-ssr
- src 源代码文件夹
- client 客户端代码
- server 服务器端代码
- share 同构代码
三步快速实现React SSR
引入要渲染的React组件
通过renderToString方法将React 组件转换为HTML 字符串
renderToString方法用于将React组件转换成HTML字符串,可通过react-dom/server 导入
将结果HTML字符串响应到客户端
首先我们需要使用express快速搭建一个server服务器
// http.js
import express from 'express'const app = express()app.listen(3000, () => console.log('app is running on port 3000'))export default app
将同构代码,主要为页面组件代码,放到share 文件夹下
webpack打包配置
这时候我们就像通过node来运行我们的express服务器是会报错的:
$ node src/server/index.js
(node:8130) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
/Users/huiquandeng/projects/lg-fed-lp/my-module/react-ssr/src/server/index.js:1
import Home from '../share/pages/Home'
^^^^^^
SyntaxError: Cannot use import statement outside a module
问题:nodejs环境不支持ESModule模块系统,不支持JSX语法。
所以需要webpack工具使用babel插件对其进行转换。
const path = require('path')module.exports = {mode: 'development',target: 'node',entry: './src/server/index.js',output: {path: path.join(__dirname, 'build'),filename: 'bundle.js'},module: {rules: [{test: /\.js$/,exclude: /node_modules/,use: {loader: 'babel-loader',options: {presets: ['@babel/preset-env', '@babel/preset-react']}}}]}
}
在 package.json中配置运行命令:
"scripts": {"dev:server-build": "webpack --config webpack.server.js"
}
此时即可运行打包命令生成bundle.js 文件到build 目录下,
这时使用node命令允许该服务器就不会报错了。
$ node build/bundle.js
app is running on port 3000
尝试访问应用页面,发现报错React模块未定义。
$ node build/bundle.js
app is running on port 3000
ReferenceError: React is not defined
at eval (webpack://react-ssr/./src/server/index.js?:9:96)
回到server 的index.js 文件中,我们引入React即可。

此时服务器已经可以正常渲染React 组件中的内容。

改进: 这时候我们没改动一次代码要想页面内容生效,都需重新运行一下打包命令,这个操作可以交给我们的程序自主监测运行,减少我们的重复的手工操作,提升开发效率。
配置项目启动命令
配置服务器端webpack打包命令:
"dev:server-build": "webpack --config webapck.server.js --watch"
打包命令加入--watch 参数,可以让webpack监控文件的更改重新执行build打包命令生成build目录下多的文件。
配置服务端启动命令:
"dev:server-run": "nodemon --watch build --exec \"node build/bundle.js\""
该命令使用了nodemon进行node程序的监控,通过--watch 监控指定文件夹中文件的变化,当有变化时重新运行服务器启动命令:node build/bundle.js。
此时开两个终端分别运行以上两个命令即可实现文件变化的监控。

为组件元素附加事件的方式
思路: 在客户端对组件进行二次渲染,为组件元素附加事件。
客户端二次渲染的方法:hydrate
使用hydrate 方法对组件进行渲染,为组件元素附加事件。
该方法在实现渲染的时候,会复用原本已经存在的DOM节点,减少重新生成节点以及删除原本DOM节点的开销。
可以通过react-dom模块引入。
import ReactDOM from 'react-dom'
ReactDOM.hydrate(<App />, document.querySelector('#root'))
在src/client 文件夹中新建index.js文件
import React from 'react'
import ReactDOM from 'react-dom'
import Home from '../share/pages/Home'ReactDOM.hydrate(<Home />, document.querySelector('#root'))
客户端React打包配置
webpack打包配置 webpack.client.js
打包目的:转换JSX语法,转换浏览器不识别的高级JavaScript 语法
输出目标位置:public 目录
const path = require('path')module.exports = {mode: 'development',// target: 'es5',entry: './src/client/index.js',output: {path: path.join(__dirname, 'public'),filename: 'main.js'},module: {rules: [{test: /\.js$/,exclude: /node_modules/,use: {loader: 'babel-loader',options: {presets: ['@babel/preset-env', '@babel/preset-react']}}}]}
}
打包启动命令配置
"dev:client-build": "webpack --config webpack.client.js --watch"
添加客户端包文件请求链接
在响应客户端的HTML代码中添加script 标签,请求客户端JavaScript打包文件main.js
`<html><head><title>React SSR Base</title></head><body><div id='root'>${content}</div><script src='main.js'></script></body></html>`
在server端的服务器中设置静态资源文件目录
在对网页进行访问之前还需要做一步工作,就是为服务器设置静态资源文件目录。
import express from 'express'const app = express()
// 设置静态资源请求目录
app.use(express.static('public'))app.listen(3000, () => console.log('app is running on port 3000'))export default app
此时就可以为组件元素添加事件了:
import React from 'react'export default function Home () {return (<div onClick={() => console.log('Hello onClick trigger')}>Home works run with nodemon cli</div>)
}
此时就已经可以成功为组件附加上点击事件:

注意在V18版本的的react中hydrate 方法不再使用,改用hydrateRoot代替:
// Before
import { hydrate } from 'react-dom';
const container = document.getElementById('app');
hydrate(<App tab="home" />, container);// After
import { hydrateRoot } from 'react-dom/client';
const container = document.getElementById('app');
const root = hydrateRoot(container, <App tab="home" />);
// Unlike with createRoot, you don't need a separate root.render() call here.
优化:合并webpack配置
服务器端和客户端的webpack配置文件存在重复,可将重复的部分配置抽象到webpack.base.js 配置文件中。
接下来在利用webpack-merge 对文件差异部分以及重复的base部分进行合并。
// webpack.base.js
module.exports = {mode: 'development',module: {rules: [{test: /\.js$/,exclude: /node_modules/,use: {loader: 'babel-loader',options: {presets: ['@babel/preset-env', '@babel/preset-react']}}}]}
}
// webpack.client.js
const path = require('path')
const { merge } = require('webpack-merge')
const baseConfig = require('./webpack.base')const config = {entry: './src/client/index.js',output: {path: path.join(__dirname, 'public'),filename: 'main.js'}
}module.exports = merge(baseConfig, config)
// webpack.server.js
const path = require('path')
const { merge } = require('webpack-merge')
const baseConfig = require('./webpack.base')const config = {target: 'node',entry: './src/server/index.js',output: {path: path.join(__dirname, 'build'),filename: 'bundle.js'}
}module.exports = merge(baseConfig, config)
优化:合并项目启动命令
三个命令启动项目显得比较繁琐,所以我们需要一个工具帮我们合并多个命令,运行一个命令即可把完整项目运行起来。这个工具就是: npm-run-all
$ npm i npm-run-all
配置命令:
"dev": "npm-run-all --parallel dev:*"
--parallel 参数:表示同时执行多个命令。
这样一来,我们的项目开发启动命令只需要运行dev命令即可:
$ npm run dev

优化:服务器端打包文件体积优化
开始前我们先来看一下目前打包出来的bundle.js文件的大小:
asset bundle.js 1.54 MiB [compared for emit]
问题:显然我们这么简单的一个应用,这个文件大小显得有点过大了。
究其原因是实际上是在打包是把node代码环境中的一些系统模块打包到了我们的应用当中。
所以接下来我们就要对这部分的代码进行打包优化,通过webpack的配置把这些不必要的系统代码剔除,避免它们被打包盗目标文件中。
解决方法:需要用到 webpack-node-externals
const path = require('path')
const { merge } = require('webpack-merge')
const nodeExternals = require('webpack-node-externals')const baseConfig = require('./webpack.base')const config = {target: 'node',entry: './src/server/index.js',output: {path: path.join(__dirname, 'build'),filename: 'bundle.js'},externals: [nodeExternals()]
}module.exports = merge(baseConfig, config)
重新运行打包:
asset bundle.js 7.96 KiB [emitted]
优化过后的体积只有8kb左右,非常的nice。
优化:代码拆分
在一个项目中,同构代码也需要实现前后端代码分离,所以我们需要将启动服务器代码和渲染代码进行模块化拆分。通过优化代码组织方式,渲染React组件代码是独立功能,所以把它从服务器端入口文件进行抽离。
把原本server/index.js中的HTML字符串渲染的内容抽离到server/render.js:
import React from 'react'
import Home from '../share/pages/Home'
import { renderToString } from 'react-dom/server'export default (Component = Home) => {const content = renderToString(<Component />)return `<html><head><title>React SSR Base</title></head><body><div id='root'>${content}</div><script src='main.js'></script></body></html>`
}
拆分抽离后的index.js:
import app from './http'
import render from './render'app.get('/', (req, res) => {// 未来会抽取出来作为入口html模版文件res.send(render())
})
实现服务器端路由
实现路由支持分析
在React SSR项目中需要实现两端路由
客户端路由是用于支持用户通过点击链接的形式跳转页面。
服务器端路由是用于支持用户直接从浏览器地址栏中访问地址。
客户端和服务器端共用一套路由规则。
也就是说路由规则属于share公共代码
在src/share/pages目录下新建页面组件home 和 list:
import React from 'react'
import routes from '../routes'export default function List () {return (<div><ul>{routes.map(route => {return (<li key={route.path}><a href={route.path}>{route.component.name}</a></li>)})}</ul></div>)
}
接着在src/share目录下新建路由规则routes.js文件,其内部采用数组对象的形式。使得规则较为通用,可在node环境中直接使用。
import Home from './pages/Home'
import List from './pages/List'export default [{path: '/',component: Home,exact: true},{path: '/list',component: List}
]
这一步需要用到两个支持库: react-router-dom 和 react-router-config
$ npm i react-router-dom react-router-config
给render.js中的渲染函数添加路由支持代码:
import React from 'react'
import { renderToString } from 'react-dom/server'
import { StaticRouter } from 'react-router-dom'
// renderRoutes方法旨在把数组形式的路由规则转换为组件形式的路由规则
import { renderRoutes } from 'react-router-config'
import routes from '../share/routes'export default req => {const content = renderToString(// 根据请求req的path 匹配对应的路由获取页面组件渲染成字符串<StaticRouter location={req.path}>{renderRoutes(routes)}</StaticRouter>)return `<html><head><title>React SSR Base</title></head><body><div id='root'>${content}</div><script src='main.js'></script></body></html>`
}
同时需要修改服务器端的路由处理匹配规则为 * ,这样就可以接收到任何的客户端路由请求:
import app from './http'
import render from './render'app.get('*', (req, res) => {res.send(render(req)) // 把req传递给渲染函数render,以便可以进行路由支持
})
这里有个坑要留意:react-router的 v5 -> v6 有个升级指南说到react-router-config在v6中被合并并移除了,v6中使用useRoutes方法代替
这样以来,useRoutes是个钩子函数,我们得为页面路由组件列表创建一个入口组件App.js:
import React from 'react'
import { useRoutes } from 'react-router'
import routes from '../routes'export default function App () {const element = useRoutes(routes)return element
}
则服务端渲染代码对应修改为:
import React from 'react'
import { renderToString } from 'react-dom/server'
import { StaticRouter } from 'react-router-dom/server'
// renderRoutes方法旨在把数组形式的路由规则转换为组件形式的路由规则
// import { useRoutes } from 'react-router'
// import routes from '../share/routes'
import App from '../share/pages/App'export default req => {// StaticRouter根据请求req的 url 匹配对应的路由获取页面组件渲染成字符串const content = renderToString(<StaticRouter location={req.url}><App /></StaticRouter>)return `<html><head><title>React SSR Base</title></head><body><div id='root'>${content}</div><script src='main.js'></script></body></html>`
}
实现客户端路由
客户端hydrate渲染的代码修改为:
import React from 'react'
// import ReactDOM from 'react-dom'
import { hydrateRoot } from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
// import { useRoutes } from 'react-router'
// import routes from '../share/routes'
import App from '../share/pages/App'const container = document.querySelector('#root')
// ReactDOM.hydrate(<Home />, container)const root = hydrateRoot(container,<BrowserRouter><App /></BrowserRouter>
)
Home页面添加Link组件实现客户端页面路由跳转:
import React from 'react'
import { Link } from 'react-router-dom'
export default function Home () {return (<><div onClick={() => console.log('Hello onClick trigger')}>Home works run with nodemon cli{' '}</div><Link to='/list'>navigate to list page</Link></>)
}
实现客户端Redux
思路分析:
SSR同样需要实现两端的Redux,
客户端Redux就是通过JavaScript管理store 中的数据。
服务器端Redux 就是在服务器端搭建一套Redux 代码,用于管理组件中的数据。
客户端和服务器端共用一套Reducer 代码。
创建Store的代码由于参数传递不同,所以不可以共用。
首先,创建客户端的store
import { configureStore } from '@reduxjs/toolkit'
import todosReducer from './features/todos/todosSlice'
import usersReducer from './features/users/usersSlice'export const store = configureStore({reducer: {todos: todosReducer,users: usersReducer}
})
创建状态数据切片并导出相对应的actions 和 reducers
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
import axios from 'axios'// await axios.get('https://jsonplaceholder.typicode.com/users');
export const loadUsers = createAsyncThunk('users/loads',// (payload, thunkAPI) => {// axios// .get(payload)// .then(response => thunkAPI.dispatch(setUsers(response.data)))// }payload => {return axios.get(payload).then(response => response.data)}
)const usersSlice = createSlice({name: 'users',initialState: [],reducers: {userAdded (state, action) {state.push({id: action.payload.id,text: action.payload.text,completed: false})},addUser: {prepare: user => {return { payload: { ...user, id: Math.ceil(Math.random() * 100) } }},reducer: (state, action) => {state.push(action.payload)}},userToggled (state, action) {const user = state.find(user => user.id === action.payload)user.completed = !user.completed},setUsers (state, action) {action.payload.forEach(user => state.push(user))}},extraReducers: {[loadUsers.fulfilled]: (state, action) => {action.payload.forEach(user => state.push(user))}}
})export const { userAdded, userToggled, setUsers } = usersSlice.actions
export default usersSlice.reducer
在应用的最外层组件使用Provider封装 并提供上面创建的store 作为store 参数
import React from 'react'
// import ReactDOM from 'react-dom'
import { hydrateRoot } from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
// import { useRoutes } from 'react-router'
// import routes from '../share/routes'
import App from '../share/pages/App'
import { store } from '../store/Store.client'
import { Provider } from 'react-redux'const container = document.querySelector('#root')
// ReactDOM.hydrate(<Home />, container)const root = hydrateRoot(container,<Provider store={store}><BrowserRouter><App /></BrowserRouter></Provider>
)
在使用store中数据的 List 页面 通过connect 连接并使用store
import React, { useEffect } from 'react'
import routes from '../routes'
import { connect } from 'react-redux'
import { loadUsers } from '../../store/features/users/usersSlice'function List ({ users, dispatch }) {useEffect(() => {try {dispatch(loadUsers('https://jsonplaceholder.typicode.com/users'))// dispatch(setTodos(data))} catch (error) {console.log(error)}}, [])return (<div>ListPage<a href='/8888'>To a not found page</a><ul>{users.map(user => {return <li key={user.id}>{user.name}</li>})}</ul></div>)
}const mapStateProps = state => {return { users: state.users }
}export default connect(mapStateProps)(List)
实现服务器端Redux
创建store
因为服务器端的 store 是在接收到请求之后才创建的,所以我们需要把store创建的代码封装在一个函数当中
import { configureStore } from '@reduxjs/toolkit'
import todosReducer from './features/todos/todosSlice'
import usersReducer from './features/users/usersSlice'
export const createStore = () => {return configureStore({reducer: {todos: todosReducer,users: usersReducer}})
}export default createStore
配置store
import { createStore } from '../store/store.server'
import app from './http'
import render from './render'app.get('*', async (req, res) => {// 接收到请求后创建服务器端storeconst store = createStore()// 未来会抽取出来作为入口html模版文件res.send(render(req, store)) // 把req传递给渲染函数render,以便可以进行路由支持
})
服务器端的数据填充
当客户端JavaScript被禁用的时候,前端的获取数据的就会失败,页面没有我们原本store中的数据。
问题:当前服务器端创建的Store是空的,组件并不能从Store中获取到任何数据。
解决:服务器端在渲染组件之前就获取到组件所需的数据。
在组件中添加loadData 方法,此方法用于获取组件所需的数据,方法被服务器端调用。
将loadData 方法保存在当前组件的路由信息对象中
服务器端接收到请求之后,根据请求地址匹配出要渲染的组件的路由信息
从路由信息中获取组件中的loadData 方法并调用方法获取组件所需的数据
当数据获取完成后再渲染组件并将结果响应给客户端
List页面组件初始化时需要对已经在服务器端渲染过的内容做判断,避免重复加载数据产生二次渲染报错。
import React, { useEffect } from 'react'
import routes from '../routes'
import { connect } from 'react-redux'
import { Link } from 'react-router-dom'
import { loadUsers } from '../../store/features/users/usersSlice'function List ({ users, dispatch }) {useEffect(() => {try {// 这里做数据长度判断是为了避免服务端已经渲染过一遍的情况下页面组件初始化时再次渲染users.length === 0 &&dispatch(loadUsers('https://jsonplaceholder.typicode.com/users'))// dispatch(setTodos(data))} catch (error) {console.log(error)}return () => {console.log('Component unmounted')// 卸载回调window.INITIAL_STATE = undefined}}, [])return (<div>ListPage<Link to='/8888'>To a not found page</Link><ul>{users.map(user => {return <li key={user.id}>{user.name}</li>})}</ul></div>)
}const mapStateProps = state => {return { users: state.users }
}
// 添加loadData 方法, 被服务器端调用
const loadData = async store => {return store.dispatch(loadUsers('https://jsonplaceholder.typicode.com/users'))
}// export default connect(mapStateProps)(List)
// 把页面组件封装成路由对象所需的内容
export default {element: connect(mapStateProps)(List),loadData
}
路由信息对象数组,List对象结构中包含loadData 函数。
import React from 'react'
import Home from '../share/pages/Home'
import List from '../share/pages/List'
import NotFound from './pages/NotFound'export default [{path: '/',element: <Home />,exact: true},{path: '/list',// element: <List />...List,element: <List.element />},{path: '*',element: <NotFound />}
]
服务器端接收到请求后,获取当前请求路径对应的页面组件路由对象信息,并调用其中的获取数据方法loadData,并把后端的store对象传递进去以便获取数据后调用dispatch触发action更新state。
import routes from '../share/routes'
import { createStore } from '../store/store.server'
import app from './http'
import render from './render'
import { matchRoutes } from 'react-router'app.get('*', async (req, res) => {// 接收到请求后创建服务器端storeconst store = createStore()// 获取请求地址// 获取路由配置信息// 根据地址匹配出要渲染的组件的路由对象信息const promises = matchRoutes(routes, req.path).map(({ route }) => {// 如何才能知道数据什么时候获取完成if (route.loadData) return route.loadData(store)})// 数据获取完成后将渲染结果响应给客户端Promise.all(promises).then(() => {res.send(render(req, store)) // 把req传递给渲染函数render,以便可以进行路由支持})
})
最后再响应渲染结果之前的后端渲染环节,给页面window挂载INITIAL_STATE记录当前服务器store数据状态,作为客户端的store的初始化状态。
window.INITIAL_STATE = ${serialize(store.getState())}
import React from 'react'
import { renderToString } from 'react-dom/server'
import { StaticRouter } from 'react-router-dom/server'
import { Provider } from 'react-redux'
import serialize from 'serialize-javascript'
// renderRoutes方法旨在把数组形式的路由规则转换为组件形式的路由规则
// import { useRoutes } from 'react-router'
// import routes from '../share/routes'
import App from '../share/pages/App'
// import { store } from '../store/store.server'export default (req, store) => {// StaticRouter根据请求req的 url 匹配对应的路由获取页面组件渲染成字符串const content = renderToString(<Provider store={store}><StaticRouter location={req.url}><App /></StaticRouter></Provider>)return `<html><head><title>React SSR Base</title></head><body><div id='root'>${content}</div><script>// 这里是为了避免前后端页面二次渲染出现错误提示// Warning: Did not expect server HTML to contain a <li> in <ul>. window.INITIAL_STATE = ${serialize(store.getState())}</script><script src='main.js'></script></body></html>`
}
window.INITIAL_STATE = ${serialize(store.getState())}
这句代码存在的意义是为了给客户端的hydrate提供store的初始化的状态值。
以消除React的警告:
Warning: Did not expect server HTML to contain a <li> in <ul>.
分析:
该警告出现的原因是客户端Store在初始化的状态是没有数据的,在渲染组件的时候生成的是空ul,但是服务器端是先获取数据在进行的组件渲染,其生成的页面元素是有li 子元素的ul,hydrateRoot方法在对比时发现两者不一致,所以报了个警告。
解决思路:
将服务器端获取到的数据回填给客户端,让客户端拥有初始数据。
import { configureStore } from '@reduxjs/toolkit'
import todosReducer from './features/todos/todosSlice'
import usersReducer from './features/users/usersSlice'export const store = configureStore({reducer: {todos: todosReducer,users: usersReducer},preloadedState: window.INITIAL_STATE
})
防止XSS攻击
就是说当服务器端返回的数据中包含恶意的JavaScript代码多的时候,我们要阻止这些恶意代码多的执行。即:转义状态的恶意代码。
也就是说我们使用服务器端渲染给客户端返回的页面内容中包含的JavaScript代码片段,是可能被恶意利用的,不能简单的使用JSON.stringify()方法进行字符串序列化,而是需要进行转义,以防止XSS攻击。
例如:
let response = {name: '</script></script>setInterval(function(){alert(1)}, 1000)</script>',age: 18
}
这时候我们在服务器端返回数据前就需要通过一个serialize方法,它是从serialize-javascript这个包提供的。
import serialize from 'serialize-javascript'const initialState = serialize(store.getState())
后续我们会继续深入学习当前流行的react服务端渲染支持框架Next.js和Gatsby。
Next.js 集成框架
Gatsby
相关文章:

React 服务端渲染
React 服务器端渲染概念回顾什么是客户端渲染CSR(Client Side Rendering)服务器端只返回json数据,Data和Html的拼接在客户端进行(渲染)。什么是服务器端渲染SSR(Server Side Rendering)服务器端返回数据拼接过后的HTML,Data和Html…...

【算法设计-搜索】回溯法应用举例(1)
文章目录0. 回溯模板1. 走楼梯2. 机器走格子,但限定方向3. 中国象棋,马走日字4. 走迷宫5. 积木覆盖0. 回溯模板 搜索算法中的回溯策略,也是深度优先搜索的一种策略,比较接近早期的人工智能。毕竟,搜索是人工智能技术中…...

C++基础了解-23-C++ 多态
C 多态 一、C 多态 多态按字面的意思就是多种形态。当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。 C 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。 下面的实例中,基类 Shape 被…...

【GNN/深度学习】常用的图数据集(资源包)
【GNN/深度学习】常用的图数据集(图结构) 文章目录【GNN/深度学习】常用的图数据集(图结构)1. 介绍2. 图数据集2.1 Cora2.2 Citeseer2.3 Pubmed2.4 DBLP2.5 ACM2.6 AMAP & AMAC2.7 WIKI2.8 COCS2.9 BAT2.10 EAT2.11 UAT2.12 C…...

Clickhouse中bitmap介绍以及计算留存Demo
前言 参考了腾迅的大数据分析-计算留存,能够根据用户自定义属性,以及玩家行为进行留存的计算。最初计算留存的方法使用的是clickhosue自带的rentention函数,使用这个函数不用关注太多细节,只需要把留存条件放入函数即可。但是这个如果需要关联用户属性,就比较麻烦了。因此…...

大数据是什么?学习后能找高薪工作么
大数据是什么,比较官方的定义是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。 简单来说,大数据就是结构化的…...

如何提取视频中的音频转文字?分享提效减负视频转文字方法
最近我在学做短视频,就看了很多博主怎么做视频,像他们的拍摄方法、剪辑角度还有怎么写文案。我一开始只看了一两个博主,写文案时就是边看视频边打字,这视频量少还好,视频多了就觉得这种方法好费时间,感觉一…...

脑机接口科普0018——前额叶切除手术
本文禁止转载!!! 首先说明一下,前额叶切除手术,现在已经不允许做了。 其次,前额叶切除手术,发明这个手术的人居然还获得了诺贝尔奖。太过于讽刺。1949年的那次诺贝尔医学奖(就是我…...

FPGA工程师面试——基础知识
1. 简述FPGA等可编程逻辑器件设计流程 答:系统设计电路构思,设计说明与设计划分, 电路设计与输入(HDL代码、原理图), 功能仿真与测试, 逻辑综合, 门级综合, 逻辑验证与测…...

全国青少年软件编程(Scratch)等级考试一级真题——2019.12
青少年软件编程(Scratch)等级考试试卷(一级)分数:100 题数:37一、单选题(共25题,每题2分,共50分)1.下列关于舞台的描述,不正确的是?( )…...

【Integrated Electronics系列——数字电子技术基础】
目录 序言...

【微信小程序】-- 页面处理总结(三十一)
💌 所属专栏:【微信小程序开发教程】 😀 作 者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! &…...

Spring Batch使用详细例子
Spring Batch 是一个开源的批处理框架,它提供了一种简单的方式来处理大规模的数据处理任务。它基于 Spring 框架,可以与 Spring 的其他组件无缝集成,如 Spring Boot、Spring Data 等。本文将介绍如何使用 Spring Batch 进行批处理任务。 1. 准…...

漏洞预警|Apache Dubbo 存在反序列化漏洞
棱镜七彩安全预警 近日网上有关于开源项目Apache Dubbo 存在反序列化漏洞,棱镜七彩威胁情报团队第一时间探测到,经分析研判,向全社会发起开源漏洞预警公告,提醒相关安全团队及时响应。 项目介绍 Apache Dubbo 是一款 RPC 服务开…...

Tomcat源码分析-spring boot集成tomcat
SPI 在分析源码前,我们先来了解下 spring 的 SPI 机制。我们知道,jdk 为了方便应用程序进行扩展,提供了默认的 SPI 实现(ServiceLoader),dubbo 也有自己的 SPI。spring 也是如此,他为我们提供了…...

一个古老的html后台的模板代码
效果图下: css部分代码:/* CSS Document / body{font-family:“宋体”, Arial,Verdana, sans-serif, Helvetica;font-size:12px;margin:0;background:#f4f5eb;color:#000;} dl,ul,li{list-style:none;} a img{border:0;} a{color:#000;} a:link,a:visit…...

支持向量回归删除异常值Python
1、支持向量回归(SVR)原理 支持向量回归(Support Vector Regression,SVR)不仅可以用于预测,还可以用于异常值检测。其基本思路是训练一个回归模型,通过对每个数据点进行预测,并计算…...

手把手开发一门程序语言JimLang (2)
根据爱因斯坦的相对论,物体的质量越大,时间过得越快,所以托更对于我的煎熬,远远比你们想象的还要痛苦…今天给大家来盘硬菜,也是前些时日预告过的JimLang的开发过程… Let’s go !!! 语法及解析 JimLang.g4 这里我们…...

DSF深度搜索时到底是如何回溯的(小tip)
这一段让我迷了两次,为什么回溯的时候,恢复了最后一位,往上递归一层之后,把最后一位填在它前一位,但是原本的前一位没有恢复,最后一位要怎么办?其实这还是递归没明白 也就是这一步是如何实现的 …...

Rust Web入门(八):打包发布
本教程笔记来自 杨旭老师的 rust web 全栈教程,链接如下: https://www.bilibili.com/video/BV1RP4y1G7KF?p1&vd_source8595fbbf160cc11a0cc07cadacf22951 学习 Rust Web 需要学习 rust 的前置知识可以学习杨旭老师的另一门教程 https://www.bili…...

synchronize优化偏向锁
偏向锁 轻量级锁在没有竞争时(只有自己一个线程),仍然会尝试CAS替换mark word; 会造成一定的性能的损耗; JDK6之中引入了偏向锁进行优化,第一次使用时线程ID注入到Mark word中,之后重入不再进…...

算法习题之动态规划
动态规划习题1 打印n层汉诺塔从最左边移动到最右边的全部过程习题2 给你一个栈,请你逆序这个栈,不能申请额外的数据结构,只能使用递归函数。 如何实现?习题3 打印一个字符串的全部子序列,打印一个字符串的全部子序列,…...

顺序表【数据结构】
文章目录:star2:1. 顺序表概念:star2:2. 框架3. 基本功能3.1 头文件:star:3.2 初始化:star:3.3 扩容:star:3.4 打印:star:3.5 尾插:star:3.6 头插:star:3.7 尾删:star:3.8 头删:star:3.9 指定插入:star:3.10 指定删除:star:3.11 查找:star2:3.12 注意事项4. 顺序表的缺点&#…...

SNAP中根据入射角和干涉图使用波段计算器计算垂直形变--以门源地震为例
SNAP中根据入射角和相干图使用波段计算器计算垂直形变--以门源地震为例0 写在前面1 具体步骤1.1 准备数据1.2 在SNAP中打开波段运算Band Maths1.3 之前计算的水平位移displacement如下图数据的其他处理请参考博文在SNAP中用sentinel-1数据做InSAR测量,以门源地震为例…...

Ubuntu20.04中Docker安装与配置
一、安装 1、卸载可能存在的旧版本 sudo apt-get remove docker docker-engine docker-ce docker.io2、更新apt包索引 sudo apt-get update显示“正在读取软件包列表… 完成” 3、安装以下包以使apt可以通过HTTPS使用存储库(repository) sudo apt-get install -y apt-tran…...

pytorch权值初始化和损失函数
pytorch权值初始化和损失函数 权值初始化 梯度消失与爆炸 针对上面这个两个隐藏层的神经网络,我们求w2的梯度 可以发现,w2的梯度与H1(上一层网络的输出)有很大的关系,当h1趋近于0时,w2的梯度也趋近于0&am…...

maven将jar文件上传至本地仓库及私服
maven官方仓库有些依赖并不存在,现在项目都是maven直接获取jar,当maven获取不到时,需要我们把jar上传至maven仓库。已 ImpalaJDBC41.jar 文件为例,如:希望上传后,设置的依赖为:<dependency&g…...

前端学习第三阶段-第1、2章 JavaScript 基础语法
01第一章 JavaScript网页编程课前导学 1-1 JavaScript网页编程课前导学 02第二章 JavaScript 基础语法 2-1 计算机基础和Javascript介绍 01-计算机基础导读 02-编程语言 03-计算机基础 04-JavaScript初识导读 05-初始JavaScript 06-浏览器执行JS过程 07-JS三部分组成 08-JS三种…...

hibernate学习(二)
hibernate学习(二) 一、hibernate常见配置: 1.XML提示问题配置: 二、hibernate映射的配置: (1)class标签的配置: 标签用来建立类与表之间的映射关系属性: 1.name&…...

平安银行LAMBDA实验室负责人崔孝林:提早拿到下一个计算时代入场券
量子前哨重磅推出独家专题《“量子”百人科学家》,我们将遍访全球探索赋能“量子”场景应用的百位优秀科学专家,从商业视角了解当下各行业领域的“量子”最新研究成果,多角度、多维度、多层面讲述该领域的探索历程,为读者解析商业…...