内部周会分享之我想说啥就说啥

114 阅读8分钟

壹🌼引

话说,电视系的一位同学,有一次要交一份电视纪录片的作业。但是他拖到最后一天下午,什么也没干。要知道,做一条片子,要拍,要写,要编,工作量很大的。
那他怎么交作业呢?
最后一天下午,他借了摄像机,打开镜头盖,开机,拖着摄像机在学校的草丛里、树荫下走了一圈。也没有编辑,原始素材一刀没剪,就把这条片子交上去了。
据说,这份作业得到了老师疯狂的表扬。为什么呢?因为他给这条片子取了一个名字——
《狗眼看世界》。

image.png 这个段子听起来荒诞,但是对我后来的工作启发巨大。
它告诉我,虽然世界还是那个世界,但只要肯换角度,哪怕只是镜头的位置稍微低一点,总能发现一些惊喜。

就拿我自己来说,在西溪新座(之前的一个办公场地)的时候,做隔壁桌的女同事,每天单趟骑行30分钟小电驴上班,我就感觉非常惊讶,这也太辛苦了,特别是下雨天,为啥不乘坐公交或者地铁。23年我自己也变成了骑车通勤,结果却是骑车通勤上班这段时间,是我最期待的一件事情,有种在路上的感觉,每天路上可以看到不同来来往往的人。甚至因此还迷上了自行车和电动车改装,从而各种百度,例如电动车霍尔线是什么,电动车控制器怎么接线等等搜索。骑行让我感觉非常释压也许这就是一种换个角度看世界的惊喜。

image.png

image.png

贰🌼性能优化

看到这个标题,我想每个前端心里,大多会想,怎么又是性能优化。没办法性能优化真的很重要,因为性能优化是真正体现出前端价值的一种具体表现,同时也能区分大佬和菜鸟之间的区别。同样一个页面,用户打开需要3s和1s对于用户的留存至关重要。

从一道面试题说起

从输入 URL 到页面加载完成,发生了什么?

首先我们需要通过 DNS(域名解析系统)将 URL 解析为对应的 IP 地址,然后与这个 IP 地址确定的那台服务器建立起 TCP 网络连接,随后我们向服务端抛出我们的 HTTP 请求,服务端处理完我们的请求之后,把目标数据放在 HTTP 响应里返回给客户端,拿到响应数据的浏览器就可以开始走一个渲染的流程。渲染完毕,页面便呈现给了用户,并时刻等待响应用户的操作(如下图所示)。

image.png

我们将这个过程切分为如下的过程片段:

  1. DNS 解析
  2. TCP 连接
  3. HTTP 请求抛出
  4. 服务端处理请求,HTTP 响应返回
  5. 浏览器拿到响应数据,解析响应内容,把解析的结果展示给用户

我们可以做的,在减少http请求次数和减小请求体积方面,我们应该是专家。再者,服务器越远,一次请求就越慢,那部署时就把静态资源放在离我们更近的 CDN 上是不是就能更快一些? 浏览器端的性能优化,——这部分涉及资源加载优化、服务端渲染、浏览器缓存机制的利用、DOM 树的构建、网页排版和渲染过程、回流与重绘的考量、DOM 操作的合理规避等等——这正是前端工程师可以真正一展拳脚的地方。 总的来说,我们将从网络层面渲染层面两个大的维度来逐个点亮前端性能优化的技能树。

DNS 解析花时间,能不能尽量减少解析次数或者把解析前置?能——浏览器 DNS 缓存和 DNS prefetch。TCP 每次的三次握手都急死人,有没有解决方案?有——长连接、预连接、接入 SPDY 协议。这些需要和服务端同学一起完成。

性能优化方向:

image.png

React

React 中 setState 相同值为何会重新渲染?

平时业务基本都是通过react来完成的,不得不说下它。

以下代码会打印几次'render'?

export default function App() {
  const [count, setCount] = useState(0);
  console.log('render');
  return (
    <button onClick={() => setCount(6)}>
       click me
    </button>
  );
}

当我多次单击 button 时,控制台会打印 3 次“render”。对我来说,应该只有 2 次:

  1. 第一次渲染 (无需点击)

  2. 用于从 count 0 到 6 的更新(第一次点击)

个人理解,从第二次点击开始,它不应该重新渲染,因为setCount的是相同的值"6"

但是当我第二次点击的时候,就会打印第3次 "render" ;而第三次以及后续点击的时候,它就不会再打印 "render" 了。这是为什么呢?这意味着尽管更新了相同的值,它仍然会重新渲染一次。

网上看到的回答,更具体的

当不存在更新时,理论上说是不需要多余的render,这种优化策略在React源码里叫 eagerState。

这里问题出在 eagerState 判断 是否存在更新 的方式上。

react中数据都保存在fiber树中,由于双缓存机制,实际存在至少2棵fiber树。当我们标记A组件存在更新,实际是在A组件对应fiber树中相关的2个fiber节点中保存“存在更新”这一信息的。

当第一次点击,更新完成后,其中一个fiber中 “存在更新”这一信息被抹去,但与他相关的另一个fiber中还存在“存在更新”这一信息。所以下次更新A组件还会render,这一次会把剩下这个fiber中的“存在更新”信息抹去。

在接下来的更新中,与A相关的2个fiber中都不存在更新,A可以命中 eagerState,就不会render了

叁🌼React中的key

在React中,key属性的作用主要是辅助React进行高效的DOM diff算法,尤其是在渲染列表或者数组元素时。当一个组件的子元素是基于数组或其他可迭代数据结构生成时,为每个子元素提供一个稳定的、唯一的key属性是非常重要的。

  1. 高效更新

    • 当父组件的状态发生变化,导致子组件需要重新渲染时,React会通过比较新旧虚拟DOM树来决定如何最小化对实际DOM的操作。
    • 如果子元素带有key,React可以根据这个标识来快速识别出哪些元素发生了变化(例如:被移动、插入或删除),而不是默认情况下逐个元素进行比较,这样可以极大地提高性能。
  2. 确定性

    • key应该是一个稳定的标识符,即它在列表项目的相对位置改变时其值不应该变。如果项目的内容或顺序发生改变,但key保持不变,则React知道该项目只是被移动了,而非创建了一个新的组件实例。
  3. 避免不必要的重渲染

    • 即使列表中的元素内容没有变化,仅仅是因为它们的位置变动,如果没有keykey不唯一,React可能无法准确判断而选择销毁并重新创建这些元素,导致不必要的性能损耗和丢失内部状态的问题。

总结来说,在React中使用key是为了帮助React更准确、高效地追踪列表中元素的变化情况,从而提升整个UI更新过程中的性能表现。

列表使用index为key带来的问题,在线demo

image.png

image.png

嗯,算是抛砖引玉了,虽然是两个比较基础的知识点,但是联想到平时业务开发的时候,有很多地方和这两个知识点有关,需要彻底搞清需要看源码(ps: 我自己没看,就是看别人的读后总结)。

肆🌼前端构建工具

构建工具,就没认认真真学过,24年必须高低整一个。赋一个工具使用调查网站,不过数据停止在2021年,调查网站

image.png

伍🌼设计模式,借用一句歌词“你是我最熟悉的陌生人”。

即使是在瞬息万变的前端领域,也存在一些具备“一次学习,终生受用”特性的知识。设计模式算一个。

在软件工程中,设计模式(Design Pattern)是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案。 ——维基百科

像 User 这样当新建对象的内存被分配后,用来初始化该对象的特殊函数,就叫做构造器。在 JavaScript 中,我们使用构造函数去初始化对象,就是应用了构造器模式

function User(name , age, career) {
    this.name = name
    this.age = age
    this.career = career 
}

const user = new User(name, age, career)

想要走的更远,设计模式是一个必须掌握的点。

陆🌼代码之外

  1. 健康第一
  2. 存钱很重要
  3. 想到我再来补

哈哈哈,在各位大佬面前班门弄斧,与其说是分享,不如说是自我总结吧,前端各种技术各种轮子层出不穷,是一件非常好的事情,但是总有一些东西是值得我们花时间去学的,2024年希望大家都能找到自己的节奏,生活和技术都得到更好的发展。