Hello,又到了每天一次的下午茶时间。酱酱们的下午茶新增优质作者介绍和码上掘金板块,专注于发掘站内优质创作者和优质内容,欢迎大家多提宝贵意见!
本文字数 3000+,阅读时间大约需要 12 分钟。
- 【本期掘金酱的下午茶】亮点:
- 设计问能不能实现这种碎片化的效果
- useEffect 一定在页面渲染后才会执行吗
- 前端视角看上门履约:从用户下单到履约完成
- 领域驱动设计DDD在B端营销系统的实践
- 全面透彻,MySQL 正确的慢查询处理姿势
- 单例模式大全:细说七种线程安全的Java单例实现,及数种打破单例的手段!
- ……
今日主理人
本期每日掘金由 MiyueFE 负责制作。如有投稿文章,请私信👉 MiyueFE 。
PS:主理人目前正在招募中,有感兴趣的掘友们可以联系 Captain。
每日干货
主理人们会对近期(1-3 天)社区深度技术好文进行挖掘和筛选,优质的技术文章有机会出现在下方列表,排名不分先后。
前端
一名前端开发者分享了他如何实现一个类似于某个网站的效果,该网站展示了一张图像,渐进地将其分解为多个多边形。开发者首先通过F12调试工具查看了网站的源代码,并发现它使用了clip-path和polygon属性在每个div内部绘制多边形。然后,他编写了一小段JavaScript代码,从页面上获取了所需的数据,并将其存储在数组中。最后,他简单地封装了一个碎片化组件,并使用transition和delay属性为其添加了动画效果。最终,他实现了一个类似的效果,并在文章中分享了相关代码。
useEffect callback 在 React 中通常被认为是在浏览器完成渲染后异步调用的,但实际上它并不总是在渲染完成后才被调用。它可能会在渲染前同步调用执行,也可能会在渲染后异步调用。这是因为 React 内部会在渲染完毕后在 workloop 中检查是否存在剩余时间来同步调用 effect。如果组件渲染花费太多的时间,useEffect Callback 会被渲染后异步调用。相反,如果渲染并没有浪费太多时间,React 会尽可能在渲染前调用 effect Callback 执行。在用户交互行为下被执行的 effect callback 也有一些细微的差异。React 会在渲染前同步处理离散型事件导致的 effect callback,而对于连续性输入(非离散型)事件下的 effect callback,React 会根据渲染结束后是否存在剩余时间来决定是否同步调用 effect callback。总之,useEffect callback 的执行时机并不是固定在渲染前还是渲染后的某个阶段,而是会按照一定的规律从而决定是在渲染前被同步被调用还是在渲染后被异步调用。
本文介绍了在端内前端互动场景中的性能优化策略,以抖音欢笑中国年项目为例。首先,文章提到了页面资源请求数量过多会影响FMP,并且由于前端页面与宿主共享有限的进程资源,没有控制好内存水位可能导致客户端发烫、页面卡顿甚至闪退。为了保障互动页面的快速启动和运行时的稳定性,提供了一系列的性能优化策略。在启动速度优化方面,作者介绍了降低引擎初始化耗时的措施,如将引擎拆成颗粒度更小的包、移除全局自执行逻辑、优化渲染管线等。此外,在容器实例化之后加载业务页面之前创建引擎实例,从而可以更早的运行引擎初始化逻辑。游戏资源相对于前端页面资源存在的特点是类型多、数量多、文件大小不等、资源间存在依赖关系等。针对这些问题,作者提出了预请求、资源拆分及合并等优化策略。在运行时性能优化方面,文章简单介绍了互动引擎的核心渲染模块工作原理,并介绍了动态FPS、批次合并、Spine 优化等优化策略。最后,文章提到了互动引擎2.0的计划,将进一步结合跨端框架,对引擎核心渲染模块进行重构并下沉到 Native 实现,底层使用 ECS 架构和双线程的运行时架构,为业务提供更小的包体、更快的启动速度和更强的运行时性能。
上门履约服务是一种在客户指定地点提供产品或服务的业务模式,已开通200多个城市。转转上门履约服务提供上门回收、上门售后、上门寄卖、上门以旧换新等业务。从用户下单前和下单后的履约服务分别介绍相关技术实现。用户下单前需获取用户的经纬度信息或用户填写的上门服务地址信息,判断是否在履约服务区域。用户下单后,系统自动订单分配给对应工程师、通过多种方式与用户联系确认上门细节、利用地图导航和路线规划以提高履约效率。此外,质检功能被封装成SDK以供不同业务场景复用,从而提升开发效率和服务质量。
📗Next.js v14 如何实现 SSE、接入 ChatGPT Stream?
本文介绍了 SSE(Server-Sent Events),它是一种基于 HTTP 协议的服务器推送技术。与 WebSocket 不同,SSE 仅支持服务器向客户端的单向通信,且只能传输文本数据。SSE 的特点是使用 HTTP 协议,依然是单向通信,只能服务端向客户端发送,而 WebSocket 是双向通信。SSE 的应用之一是 AI 的打字流效果。文中还介绍了如何在 Next.js 中实现 SSE,包括如何创建 SSE 连接、服务端实现 SSE、客户端调用 SSE 接口等内容。最后,文中还提到了如何调用 ChatGPT Stream 接口,包括前端直接调用 ChatGPT Stream 接口和后端代理 ChatGPT Stream 接口的方法。
后端
本文提出了MySQL慢查询的问题和解决方案。原因是需要访问的数据太多,导致查询需要筛选大量数据。解决方案包括优化数据结构、应用索引策略、查询缓存和重构查询方式。优化数据结构包括选择索引的数据类型、范式与反范式等。应用索引策略包括使用B-Tree索引、聚簇索引等。查询缓存可以提高查询性能,但也会存在一些问题。重构查询方式包括复杂查询拆分和分解关联查询等。最后,文章总结了高性能查询的优化方法,包括数据结构优化、索引设计优化和应用查询优化。
本文介绍了应对软件系统复杂性的方法DDD(领域驱动设计),从战略设计、战术设计到代码架构,分享了DDD在B端营销系统设计中的实践。DDD能解决系统设计复杂性的三个问题:抽象层面的隐晦、代码层面的耦合和业务需求变化。DDD概念体系复杂,学习曲线陡峭,本文从历史上看DDD的演变,并从战略设计、战术设计和代码架构三个方面介绍DDD的落地。战略设计包括确定用例、统一语言和划分边界,战术设计是概念模型转化成类(代码)模型,代码架构是将系统设计映射为系统实现。
📗OkHttp开启线程池复用连接导致的EOFException解决方案
该文章介绍了使用 OkHttp 进行 HTTP 请求时的连接池机制,并分享了在使用过程中遇到的问题和解决方案。当使用 Connection:keep-alive 长连接时,如果服务端没有正确处理长连接,可能会导致请求失败。解决方案包括:1. 每次请求完成后主动关闭连接,但这会导致连接池失效;2. 将 OKHttpClient 的 retryOnConnectionFailure 配置为 true,使其在连接失败时重试并建立新的 TCP 连接。原文中作者最终采用了第二种方案,并指出 retryOnConnectionFailure 默认已启用,但作者在初始配置时关闭了该选项。通过将retryOnConnectionFailure设置为true,即使在出现由于服务端错误关闭 TCP 连接的情况下,OkHttp 也能重试并建立新的连接,从而使连接池仍然有用。
📗单例模式大全:细说七种线程安全的Java单例实现,及数种打破单例的手段!
单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局共用的访问点来获取这个实例。单例模式通常应用于配置管理类、线程池、各种Dao/Service对象、数据库连接池等,这些实例都可以共用,每次使用时创建一个实例反而会带来初始化损坏与额外的内存资源浪费。单例模式的实现方式有多种,包括饿汉式、懒汉式、双重锁单例(DCL)、枚举式单例、容器式单例、静态内部类、CAS自旋单例等。这些实现方式各有优缺点,需要根据实际情况选择合适的实现方式。同时,单例模式也可能会被破坏,常见的破坏手段包括通过反射机制和序列化反序列化机制。为了防止单例模式被破坏,可以在构造函数中加入判断,或者重写readResolve()方法。单例模式的学习需要掌握扎实的基础功底,包括设计模式、并发编程、Java虚拟机、反射机制、网络传输等知识。通过学习单例模式,可以帮助巩固自己的知识体系,并在面试过程中做到侃侃而谈。
📗在 Rust 中借助 libpnet 重造一个 tcpdump 的轮子
本文介绍了如何在 Rust 中使用 libpnet 库制作一个类似 tcpdump 的工具,用于捕获和显示网络中的数据包。捕获的数据包可以是流入特定网络接口(NIC)的数据包,也可以是通过 IPv4 或 IPv6 传输的 TCP 和 UDP 数据包。工具可以显示数据包的源和目标 IP 地址和端口号,以及应用层数据的十六进制数和可打印的 ASCII 字符格式。在开始编写代码之前,作者回顾了一下网络知识,包括网络分层模型、TCP/IP 协议分层模型、数据链路层、网络层、传输层和应用层等概念。接下来,作者介绍了如何使用 libpnet 捕获和处理数据包。首先,需要选择一个要监视的网络接口,并获取数据链路层的 channel。然后,通过 rx.next() 函数不断获取数据链路层中的数据包,并将其解析成结构化的数据类型 EthernetPacket。接下来,通过分析数据包的首部来确定上层网络层的协议,如 IPv4 或 IPv6,并将数据包交由网络层处理。同样,通过分析数据包的首部来确定传输层的协议,如 TCP 或 UDP,并将数据包交由传输层处理。最后,输出网络层和传输层的数据包的信息,包括源和目标 IP 地址、源和目标端口号、以及应用层数据的内容等。完整的代码可以在文末找到。通过这个简单的 tcpdump 的轮子,我们可以看到源 IP 地址、目标 IP 地址、源和目标端口号、以及 HTTP 的请求等信息。借助 libpnet,处理网络中的数据包变得非常简单,核心逻辑只有一个:分离首部和负载,然后根据首部选择下一层的协议,将负载交给下一层的协议处理。通过这个例子,我们可以看到枯燥的网络协议有了一些意思。
📖 投稿专区|下午茶
大家可以在评论区推荐认为不错的文章,并附上链接和推荐理由,有机会登上下一期。文章创建日期必须在近 1-3 天内;可以推荐自己的文章、也可以推荐他人的文章。