当前位置: 首页 > news >正文

精读《React Conf 2019 - Day2》

1 引言

这是继 精读《React Conf 2019 - Day1》 之后的第二篇,补充了 React Conf 2019 第二天的内容。

2 概述 & 精读

第二天的内容更为精彩,笔者会重点介绍比较干货的部分。

Fast refresh

Fast refresh 是更好的 react-hot-loader 替代方案,目前仅支持 react-native 平台,很快就会支持 react-dom 平台。

相比不支持 Function component、无法错误恢复、更新经常失灵的 hot reloading 来说,fast refresh 还拥有以下几个优点:

  • 状态保持。
  • 支持 Function Component Hooks。
  • 更快的更新速度。

Fast refresh 更新速度更快,是基于 Function Component 生成了 “签名”,从而最大成都避免销毁重渲染,尽可能保持对组件的 rerender 刷新。下面介绍签名机制的工作原理。

Fast refresh 对每个 Function component 都生成了一份专属签名,用以描述这个组件核心状态,当这个核心状态改变时,就只能销毁重渲染了,但对于不触及核心的修改就能进行代价非常小的 rerender。

这个签名包含了 hooks 和参数名:

// signature: "useState{isLoggedIn}"function ExampleComponent() {const [isLoggedIn, setIsLoggedIn] = useState(true);
}

比如当参数名变更时,这个组件的逻辑已发生改动,此时只能销毁并重渲染了。因此实际上通过对签名的对比来判断是否要销毁并重刷新组件:

// signature: "useState{isLoggedOut}"function ExampleComponent() {const [isLoggedOut, setIsLoggedOut] = useState(true);
}

同理,当 hooks 从 useState 改成了 useReducer,签名也会发生变化从而导致彻底的重渲染。

但除此之外,比如对样式的修改、Dom 结构的修改都不会触发签名的变化,从而保证了 “对不触及逻辑的改动进行高效的轻量 renreder”。

然而 Fast refresh 也有如下局限性:

  • 还不能友好支持 Class component。
  • 混合导出 React 和非 React 组件时无法精确的 hot reload。
  • 更高的内存要求。

可以看到,Fast Refresh 随着功能推广与内置,现在已经覆盖了 Facebook 95% 以上 hot reload 场景了:

这部分内容不仅揭开了 hot reload 技术内幕,还对其功能进行了进一步优化,2019 年的 React 开发体系已经进入精细化阶段。

重写 React devtools

React devtools 的更新终于被正式介绍了,本来笔者以为新的 devtools 只是支持了 hooks,但听完分享后发现还有更多有用的改进,包括:

  • 更高的性能。
  • 更多特性支持。
  • 更好用户体验。

找到节点渲染链路

并不是每个 React 节点都参与渲染,新版 React devtools 可以展示出 rendered by:

调试 Suspense

在 Day1 中讲到的 Suspense 特性可以在 React devtools 调试了:

通过点击时钟 icon,可以模拟 Suspense 处于 pendding 或 ready 状态。

增强调试能力

可以通过点击直接跳转到组件源码:

最新版已增强至点击按钮后直接通过 Source 打开源码位置,这样可以快速通过 UI 寻找到代码。同时还可以看到,通过点击 debugger 按钮将当前组件信息打到控制台调试。

除此之外还可以动态修改组件的 props 与 hook state,大大增强了调试能力。

profiler

分析工具也得到了增强,现在可以看到每个组件被渲染了几次以及重新渲染的原因:

比如上图组件被渲染了 4 次,主要有两个原因:Hooks 改变与 Props 改变。

除此之外,还优化了更多细节体验,比如高亮搜索、HOC 的展示优化、嵌套层级过多时不会占用过多的横向宽度等等。

react codemod

codemod 是一个代码重构的方式,通过 AST 方式精准触达代码,我们可以认为 codemod 是一个更聪明的“查找/替换”。

codemod 主要有以下三种使用方式:

  • 重命名。
  • 代码排序。
  • 一定程度的代码替换。

接下来就讲到 react codemod 了,它是 react 场景的 codemod 解决方案,facebook 是这么使用 react codemod 的:

  • 迁移 facebook 代码。
  • 涉及几万个组件。
  • 修复了 3500 个文件的 React.PropTypes。
  • 修复了 8500 个文件的生命周期 unsafe。
  • 修复了 20000 个文件的 createClass 转 JSX。

使用方式:

npx react-codemod React-PropTypes-to-prop-types

可以看到,通过 cli 对文件进行一次性重构处理。除此之外,再列举几种使用场景:

  • create-element-to-jsx 将 React.createElement 转换为 JSX。
  • error-boundaries 将 unstable_handleError 改为 componentDidCatch
  • findDOMNode 将 React.createClassthis.getDOMNode() 改为 React.findDOMNode
  • sort-comp 将 Class Component 生命周期按照规范排序,eslint-plugin-react 插件也有相同能力。

理论上来讲,所有 codemode 做的事情都可以替换为 eslint 的 autofix 来完成,比如 sort-comp 就同时被 codemode 和 eslint 支持。

Suspense

要理解 Suspense,就要理解 Suspense 与普通 loading 有什么区别。

从代码角度来说,Suspense 可以类比为 try/catch 的体验。为了简化代码复杂度,我们可以用 try/catch 包裹代码,从而简化 try 区块代码复杂度,并将兜底代码放在 catch 区块:

try {// 只要考虑正确情况
} catch {// 错误时 fallback
}

Suspense 也一样,它在渲染 React 组件时如果遇到了 Promise 抛出的 Error,就会进入 fallback,所以 fallback 含义是 Loading 中状态:

<Suspense fallback={<Spinner />}><ProfilePage />
</Suspense>

与此同时,实际业务组件中的取数也不需要担心取数是否正在进行中,只要直接处理拿到数据的情况就好了:

function ProfileDetails() {// 直接使用 user,不用担心失败。const user = resource.user.read();return <h1>{user.name}</h1>;
}

进一步的,如果要处理组件渲染的异常,再使用 ErrorBoundary 包裹即可,此时的 fallback 含义是组件加载异常的错误状态:

function Home(props) {return (<ErrorBoundary fallback={<ErrorMessage />}><Suspense fallback={<Placeholder />}><Composer /></Suspense></ErrorBoundary>);
}

Suspense 模式的取数好处是 “fetch on render”,即渲染与取数同时进行,而普通模式的取数是 “fetch after render”,即渲染完成后再通过 useEffect 取数,此时取数时机已晚。

队列加载

假设 ComposerNewsFeed 组件内部都通过 useQuery 取数,那么并行取数时加载机制如下:

这可能有两个问题:组件内部加载顺序不统一与组件间加载顺序不统一。

如果组件内部有图片,可能图片与组件渲染实际不一致,此时可以利用 Suspense 统一 hold 所有子组件的特性,将图片加载改为 Suspense 模式:

<div><YourImage src={uri} alt={...} /><MoreComposer />
</div>

同一个 Suspense 可以等待所有子元素都 Ready 后才会一把渲染出 UI,因此可以看到网页被一次性刷新而不是分部刷新。

第二个问题是组件间加载顺序不统一,可能导致先渲染了文章内容,再渲染出文章头部,此时如果区块高度不固定,文章头部可能会撑开,导致文章内容下移,用户的阅读体验会遭到打断。可以通过 suspense ordering 解决这个问题:

function Home(props) {return (<SuspenseList revealOrder="forwards"><Suspense fallback={<ComposerFallback />}><Composer /></Suspense><Suspense fallback={<FeedFallback />}><NewsFeed /></Suspense></SuspenseList>);
}

比如 forwards 表示从上到下,那么一定会先渲染头部再渲染文章内容,这样文章内容就不会都抖动了。

Render as you fetch

相比 “fetch on render”,更高级别的优化是 “Render as you fetch”,即取数在渲染时机之前。

比如页面路由的跳转、Hover 到一个区块,此时如果取数由这个动作触发,就可以再次将取数时机提前,Facebook 为此创造了一个新的 Hook:usePreloadedQuery

用法是,在某个事件中取数,比如点击页面跳转按钮时,通过 preloadQuery 预取数,得到的结果并不是取数结果,而是一个标识,在渲染组件中,把这个标识传给 usePreloadedQuery 可以拿到真实取数结果:

// 组件 A 的 onClick
const reference = preloadQuery(query, variables);
// 组件 B 的 render
const data = usePreloadedQuery(query, reference);

可以看到,取数真正触发的时机在渲染函数执行之前,所以在 usePreloadedQuery 调用时取数肯定已经在路上,甚至已经完成。相比之下,普通的 useQuery 函数存在下面几个问题:

  • 由于取数过程存在状态变化,可能导致组件在 “取数无意义” 状态下重新渲染多次。
  • 可能取数还未完成就触发重渲染。
    • 没有取消的机制,没有清除结果的机制。
  • 没有办法唯一标识组件。

preloadQuery 的好处就是将取数时机与 UI 分离,这样可以更细粒度的控制逻辑:

  • 调用 preloadQuery 时:
    • 在组件销毁时取消取数。
    • 有新取数触发时取消取数。
    • 销毁一些轮询机制。
  • 渲染组件调用 usePreloadedQuery 时:
    • 不会再触发取数,不会触发意外的 re-render。
    • 不需要清空,因为取数不在这里发起。
    • 不需要清理轮询。

可见 preloadQuery 相比 useQuery 的确有了一些体验提升,然而这个优化比较追求极致,对大部分国内项目来说可能还走不到 facebook 这么极致的性能优化,所以投入产出比显得不是那么高,而且这个开发方式对开发者不是太友好,因为它让请求的时机割裂到两个模块中。

但毕竟用户体验是大于开发者体验的,React 尽量通过提高开发者体验来间接提高用户体验,使双方都满意,但像 preloadQuery 就无法两者兼顾了,为了用户体验可以适当的降低一些开发者体验。

如何维护代码

这个分享讲述了如何提升代码维护效率,毕竟一个月后可能连自己写的代码都看不懂了。hydrosquall 通过类比地图的方式解释了程序员是如何维护代码的。

首先看我们是如何认路的。认路分为三个层次:

  • 随意走走。
    • 通过一些地标判断方向。
  • 有方向的寻路。
    • 通过跟随同伴或者了解更多本地信息找到目的地。
  • 地图。
    • 通过 GPS 定位。
    • 通过模拟地图方式指出路线。

可以看到这三种方式是逐层递进的,那么类比到代码就有意思了:

  • 随意走走(滚动查看源代码 + ctrl/f 查找代码 + grep 搜索)。
    • 入口(找到入口节点,查看数据结构)。
    • 标记(查看代码注释、查看 README)。
    • 发信号弹(断点、console.log 等调试行为)
  • 找到方向。
    • git blame 查看 owner,或直接根据文档找到 codeowners。
  • 地图。
    • 幸运的话你可以找到一份架构流程图。

可以看到,地图有几种抽象层次,比如忽略了细节的纽约地铁线路图:

或者是包含丰富地面信息的地铁线路图:

抽象到什么层次取决于用户使用的场景,那么代码抽象也是如此。hydrosquall 做了一个工具自动分析出代码调用关系:js-callgraph

这就像路牌一样,可以更高效的看出代码结构,也包括了数据流结构,由于篇幅限制,感兴趣的同学可以看 原视频 了解更多。

写作与写代码

本章讲了写作(小说)与写代码的关联,总结出如下几个重点:

  • 写小说和写代码都是创造行为。
  • 写代码需要抽象思维,写小说也要有抽象思维构造人物和情节。
  • Show, don’t tell,写作天然就是申明式的,和数据驱动很相似。

更多可以去看 原视频。

移动端动画最佳实践

首先要使用一个真实的手机设备调试,否则可能出现 PC Chrome 一切正常,而手机上实际效果性能很差的情况!

手势下拉退出

利用 react-spring 和 react-use-gesture 做一个下滑消失的 Demo:

import { animated, useSpring } from "react-spring";
import { useDrag } from "react-use-gesture";const [{ y }, set] = useSpring(() => {y: 0;
});

首先定义一个 y 纵向位置,通过 useDrag 将拖拽操作与 UI 绑定,通过回调将其与 y 数据绑定:

const bind = useDrag(({ last, movement: [, movementY], memo = y.value }) => {if (last) {// 拖拽结束时,如果偏移量超过 50 则效果和结束一样,直接将 y 设置为 100const notificationClosed = movementY > 50;return set({y: notificationClosed ? 100 : 0,onReset: notificationClosed && removeNotification});}// y 的位置区间在 0~100set([{ y: clamp(0, 100, memo + movementY) }]);return memo;
});

useDragy 绑定后,就可以用在 UI 组件上了:

<StyledNotificationas={animated.div}onTouchStart={bind().onTouchStart}style={{opacity: y.interpolate([0, 100], [1, 0]),transform: y.interpolate(y => `translateY(${y}px)`)}}
/>

opacitytransform 与位置 y 绑定就可以做出下拉消失的效果。

滑动的洞见

接着讲到了滑动的三个洞见:

  1. 要立刻响应,任何延迟都会造成用户额外精神负担。
  2. 滚动速度衰减可以提升用户体验:

接着我们需要预测用户的意图,比如在一个类似微信消息列表页左右滑动时:

  • 是否想取消手势交互?
  • 是否想展示出更多交互按钮?
  • 是否想删除所有内容?

这需要更多设计思考。

  1. 橡皮筋滚动,即列表页可以一直向下拉,上面部分像橡皮筋一样可以被拉出空白页的效果。

在设计手势动画时要考虑三个要点:

  • 使用移动增量作为手势动画的基准点。
  • 动画和手势应该随时可以被中断,通过 springs 即可实现。
  • 完成手势后的动画速度应该与手势速度相当,这样视觉体验更自然。

最后提到了动画兼容性与性能,比如尽量只使用 transformopacity 可以保证移动端的流畅度,不同移动设备的默认手势效果不同,最好通过 touch-action 禁用默认行为以达到更好的兼容性与效果。

唱片与 React

J.Dash 拥有十年软件开发经验,同时也卖过很多唱片,他介绍了唱片行业与软件开发的共同点。

唱片行业需要音乐编排能力,这与编码能力类似,都存在良好的设计模式,并且需要团队合作,开发过程中会遇到一些痛苦的经历,但最终完成音乐和项目时都会获得满足的喜悦。

函数式编程

Declaratives UIs are the future, and the future is Comonadic. - Phil Freeman

申明式 UI 是未来,未来则是 Comonadic。

所谓申明式 UI 可以用下面的公式表达:

type render = (state: State) => View;

然后用一段公式介绍了 Comonadic:

class Functor w => Comonad w whereextract   :: w a -> aduplicate :: w a -> w (w a)extend    :: (w a -> a) -> w a -> w b

用 JS 版本做一个解释:

const Store = ({ state, render }) => ({extend: f => Store({ state, render: state => f(Store({ state, render })) }),extract: () => render(state)
});

extract 调用后会进行申明式渲染 UI,即 render(state)

extend 表示拓展,接收一个拓展函数作为参数,返回一个新的 Store 对象。这个拓展函数可以拿到 staterender 并返回新的 state 作为 extractrender 的输入。使用例子是这样的:

const App = Store({state: { msg: "World" },render: ({ msg }) => <p>Hello {msg}</p>
});App.extend(({ state }) =>state.msg === "World" ? { msg: "ReactConf" } : state
).extract(); // <p> Hello ReactConf </p>

然而尴尬的是,笔者看了很久也没看懂 Store 函数,最后运行了一下发现这个 Demo 抛出了异常 😂。

下面是笔者稍微修改后的例子,至少能跑起来:

const Store = ({ state, render }) => ({extend: f => Store({ state, render: state => render(f({ state, render })) }),extract: () => render(state)
});const app = Store({state: { msg: "Hello World" },render: ({ msg }) => console.log("render " + msg)
});app.extend(({ state }) => {return { msg: state.msg + " extend1" };}).extend(({ state }) => {return { msg: state.msg + " extend2" };}).extract(); // render Hello World extend2 extend1

然而作者的意思仍是未解之谜,希望对函数式了解的同学可以在评论区指点一下。

wick editor

wick editor 是一个开源的动画、游戏制作软件。

wick editor 是一个动画制作工具,但拓展了一些 js 编程能力,因此可以很好的将动画与游戏结合在一起:

演讲介绍了 wick editor 的演化过程:

从很简陋的 MVP 版本开始(1 周)

到 Pre-Alpha(4 月)

Alpha(5 月)

Beta(1.5 年)

重点是 1.0 版本采用 React 重写了!继 Beta 之后又经历了 1 年:

这个团队最棒的地方是,将游戏与教育结合,针对不同场景做了很多用户调研并根据反馈持续改进。

React Select

react-select 的作者 Jed Watson 被请来啦。作为一个看上去很简单组件(select)的开发者,却拥有如此大的关注量(1.8w star),那作者有着怎样的心路历程呢?

react-select 看似简单的名字背后其实有挺多的功能,比如作者列举了一些功能层面的内容:

  • autocomplete - 输入时搜索。
  • 单、多选。
  • focus 管理。
  • 下拉框层级与位置,比如可以放在根 DOM 节点,也可以作为当前节点的子元素。
  • 异步下拉框内容。
  • 键盘、触控。
  • Createble,即在搜索时如果没有内容可以动态创建。
  • 等等。

在设计层面:

  • 申明式。
  • 可以被定制。
  • 性能要求。
  • 等等。

随着 Star 逐渐上涨,越来越多的需求被提出,核心库代码量越来越大,甚至许多需求之间都是相互冲突的,而且作者每天都会被上百个 Issue 与 PR 吵醒。做一个业务 Select 可能只要 5 分钟,但做一个开源 Select 却要 5 年,原因是一个简单的 Select 如何满足所有不同业务场景?这绝对是个巨大的挑战。

比如用户即需要受控也要非受控的组件,如何满足好这个需求同时又让代码更可维护呢?

假设我们拥有一个受控的组件 SelectComponent,那么它的主要 props 是 valueonChange,如果要拓展成一个既支持 defaultValue(非受控)又支持 value(受控)的组件,我们可以创建一个 manageState 组件对 SelectComponent 进行封装:

const manageState = SelectComponent => ({value: valueProps,onChange: onChangeProp,defaultValue,...props
}) => {const [valueState, setValue] = useState(defaultValue);const value = valueProps !== undefined ? valueProps : valueState;const onChange = (newValue, actionMeta) => {if (typeof onChangeProp === "function") {onChangeProp(newValue, actionMeta);}setValue(newValue);};return <SelectComponent {...props} value={value} onChange={onChange}>
};

这样就可以组合为一个受控/非受控的综合 Select 组件:

import BaseSelect from "./Select";
import manageState from "./manageState";export default manageState(Select);

同理对异步的封装也可以放在 makeAsync 函数中:

const makeAsync = SelectComponent => ({getOptions,defaultOptions,...props
}) => {const [options, setOptions] = useState(defaultOptions);const [isLoading, setIsLoading] = useState(false);const onInputChange = async newValue => {setIsLoading(true);const newOptions = await getOptions(newValue);setIsLoading(false);setOptions(newOptions);};return (<SelectComponent{...props}options={options}isLoading={isLoading}onInputChange={onInputChange}/>);
};

可以看到,SelectComponent 是一个完全受控的数据驱动的 UI,无论是 manageState 还是 makeAsync 都是对数据处理的拓展,所以这三者之间才可以融洽的组合:

import BaseSelect from "./Select";
import manageState from "./manageState";
import makeAsync from "./async";export default manageState(Select);export const AsyncSelect = manageState(makeAsync(Select));

后面还有一些风格化、开源协作的思考,这里就不展开了,对这部分感兴趣的同学可以查看原视频了解更多。

React + 政府财政透明项目

usaspending.gov 这个网站使用 React 建设,可以查看美国政府支持财政的明细,通过流畅的体验让更多用户可以了解国家财政支出,进一步推动财政支出的透明化。由于并不涉及前端技术的介绍,主要是产品介绍,因此精读就不详细展开了。

顺便说一句,智能分析数据就用 QuickBI,QuickBI 是我们团队研发的一款智能 BI 服务平台,如果你将美国政府的财政支持作为数据集输入,你会分析得更透彻。

React + 星舰模拟器

最后介绍的是使用 React 制作的星舰模拟器,看上去像一个游戏:

有星系图、船体、驾驶员信息、武器装备、燃料、通信等等内容。甚至可以模拟太空驾驶,进行任务,可以实时多人协同。对太空迷们的吸引力很大,感兴趣的同学建议直接观看 视频。

3 总结

第二天的内容非常全面,涉及了 React API、开发者周边、codemod 工具、代码维护、写作/音乐与代码、动画、函数式编程、看似简单的 React 组件、使用 React 制作的各种脑洞大开的项目,等等。

React Conf 要展示的是一个完整的 React 世界,第一天提到了 React 是一个桥梁,正因为这个桥梁,连接了各行各业不同的人群以及不同的项目,大家都有一个共同的语言:React。

“We not only react code, but react the world”。

讨论地址是:精读《React Conf 2019 - Day2》 · Issue #217 · dt-fe/weekly

相关文章:

精读《React Conf 2019 - Day2》

1 引言 这是继 精读《React Conf 2019 - Day1》 之后的第二篇&#xff0c;补充了 React Conf 2019 第二天的内容。 2 概述 & 精读 第二天的内容更为精彩&#xff0c;笔者会重点介绍比较干货的部分。 Fast refresh Fast refresh 是更好的 react-hot-loader 替代方案&am…...

向ChatGPT高效提问模板

PS: ChatGPT无限次数&#xff0c;无需魔法&#xff0c;登录即可使用,网页打开下面 tj4.mnsfdx.net [点击跳转链接](http://tj4.mnsfdx.net/) 我想请你XXXX&#xff0c;请问我应该如何向你提问才能得到最满意的答案&#xff0c;请提供全面、详细的建议&#xff0c;针对每一个建…...

android metaRTC编译

参考文章&#xff1a; metaRTC3.0稳定版本编译指南_metartc 编译-CSDN博客 源码下载&#xff1a; Releases metartc/metaRTC GitHub 版本v6.0-b4即可...

HDFS面试重点

文章目录 1. HDFS的架构2. HDFS的读写流程3.HDFS中&#xff0c;文件为什么以block块的方式存储&#xff1f; 1. HDFS的架构 HDFS的架构可以分为以下几个主要组件&#xff1a; NameNode&#xff08;名称节点&#xff09;&#xff1a; NameNode是HDFS的关键组件之一&#xff0c;…...

Java中的IO流是什么?

Java中的IO流&#xff08;Input/Output Stream&#xff09;是Java编程语言中用于处理输入和输出操作的一种重要机制。在Java中&#xff0c;IO流被用来读取和写入数据&#xff0c;这些数据可以来自各种来源&#xff0c;如文件、网络连接、内存缓冲区等。Java的IO流提供了丰富的类…...

Spring boot 集成netty实现websocket通信

一、netty介绍 Netty 是一个基于NIO的客户、服务器端的编程框架&#xff0c;使用Netty 可以确保你快速和简单的开发出一个网络应用&#xff0c;例如实现了某种协议的客户、服务端应用。Netty相当于简化和流线化了网络应用的编程开发过程&#xff0c;例如&#xff1a;基于TCP和U…...

数码管的动态显示(二)

1.原理 这个十六进制是右边的dp为高位。 数码管的动态显示&#xff0c;在第一个计数周期显示个位&#xff0c;在第二个周期显示十位&#xff0c;在第三个周期显示百位由于人眼的视觉和数码管的特性&#xff0c;感觉就是显示了234&#xff0c;每个数码管的显示需要从输入的数据里…...

【JavaScript】数据类型转换 ① ( 隐式转换 和 显式转换 | 常用的 数据类型转换 | 转为 字符串类型 方法 )

文章目录 一、 JavaScript 数据类型转换1、数据类型转换2、隐式转换 和 显式转换3、常用的 数据类型转换4、转为 字符串类型 方法 一、 JavaScript 数据类型转换 1、数据类型转换 在 网页端 使用 HTML 表单 和 浏览器输入框 prompt 函数 , 接收的数据 是 字符串类型 变量 , 该…...

git学习(创建项目提交代码)

操作步骤如下 git init //初始化git remote add origin https://gitee.com/aydvvs.git //建立连接git remote -v //查看git add . //添加到暂存区git push 返送到暂存区git status // 查看提交代码git commit -m初次提交git push -u origin "master"//提交远程分支 …...

Day36:安全开发-JavaEE应用第三方组件Log4j日志FastJson序列化JNDI注入

目录 Java-项目管理-工具配置 Java-三方组件-Log4J&JNDI Java-三方组件-FastJson&反射 思维导图 Java知识点&#xff1a; 功能&#xff1a;数据库操作&#xff0c;文件操作&#xff0c;序列化数据&#xff0c;身份验证&#xff0c;框架开发&#xff0c;第三方库使用…...

HTML5+CSS3+JS小实例:全屏范围滑块

实例:全屏范围滑块 技术栈:HTML+CSS+JS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale…...

ctf杂项总结

1.文件无法打开 1.1.文件拓展名损坏/错误导致 方法&#xff1a; 1.使用kali当中的file命令查看&#xff0c;之后修改为正确的后缀即可 2.通过16进制编辑器打开查看文件头 3.文件头残缺/错误&#xff0c;可以先使用kail当中的file命令查看它的类型&#xff0c;之后再通过 16…...

openAI key 与ChatGPTPlus的关系,如何升级ChatGPTPLus

一、前言 先详细介绍一下Plus会员和Open API之间的区别&#xff1a; 实际上&#xff0c;这两者是相互独立的。举例来说&#xff0c;虽然您开通了Plus会员&#xff0c;并不意味着您就可以使用4.0版本的API。尽管这两个账户可以是同一个&#xff0c;但它们是完全独立的平台。 …...

KB5034441 0x80070643 reagentc.exe 无法更新引导配置数据

微软2024年1月的更新补丁正常更新会出现0x80070643错误&#xff0c;原因是正常安装系统默认的恢复分区留小了&#xff0c;通过压缩系统盘空间然后在diskgenius扩容恢复分区空间可以解决这个问题&#xff0c;但是笔者在进行上述操作时依旧出现了报错&#xff0c;按照网上的说法可…...

全网最最最详细“Jupyter command ‘jupyter-notebook‘ not found.“的解决方案

"Jupyter command jupyter-notebook not found."。这通常意味着 jupyter-notebook 命令在当前的虚拟环境中未安装或未正确安装&#xff0c;因此系统无法识别此命令。 原因分析 未安装 Jupyter Notebook: 可能你的虚拟环境中还没有安装 Jupyter Notebook。虽然 Jupyt…...

Java中常用的集合及方法(2)

在Java&#xff08;JDK8&#xff09;中&#xff0c;集合&#xff08;Collection&#xff09;是数据结构的实现&#xff0c;用于存储和操作对象集合。 集合&#xff08;Collection&#xff09;中包含的一般类或接口&#xff1a; 在这其中呢&#xff0c;我们经常使用的其实就是L…...

如何轻松打造属于自己的水印相机小程序?

水印相机小程序源码 描述&#xff1a;微信小程序。本文将为您详细介绍小程序水印相机源码的搭建过程&#xff0c;教您如何轻松打造属于自己的水印相机小程序。无论您是初学者还是有一定基础的开发者&#xff0c;都能轻松掌握这个教程。 一&#xff1a;水印相机搭建教程 1 隐…...

Qt+FFmpeg+opengl从零制作视频播放器-12.界面美化

Qt是一个跨平台的C++图形用户界面应用程序开发框架,提供了丰富的功能和工具来创建美观的界面。以下是一些方法,可以帮助美化Qt界面: 使用样式表(QSS):Qt支持通过QSS(Qt样式表)来自定义界面的外观。QSS是一种类似于CSS的语言,可以用来设置控件的颜色、字体、边框等样式…...

【测试】1. 概念 + 基础篇

概念篇 测试相较于开发岗位而言&#xff0c;如果同学们的编程能力稍微弱一些&#xff0c;可以尝试测试方向&#xff08;更简单&#xff09; 1. 什么是软件测试 最常见的理解是&#xff1a;软件测试就是找BUG&#xff0c;发现缺陷。 早期&#xff0c;人们更多的将测试看成是对…...

【数据结构取经之路】快速排序的非递归实现

概述 递归实现快速排序在一些场景下有栈溢出的风险&#xff0c;下面就谈谈如何用非递归的方法实现快速排序。 非递归实现的思想 递归实现与非递归实现快速排序的本质是一致的&#xff0c;效率并不会因为用了非递归实现而有所提升。递归实现快速排序的本质就在于通过递归&…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

自然语言处理——循环神经网络

自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元&#xff08;GRU&#xff09;长短期记忆神经网络&#xff08;LSTM&#xff09…...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...