面试官:你做过什么有亮点的项目吗?
前言
面试中除了问常见的算法网络基础,和一些八股文手写体之外,经常出现的一个问题就是,你做过什么项目吗?
面试官其实是想看看你做过什么有亮点的项目, 其实大家日常做的项目都差不多,增删改查,登录注册,弹窗等等,所谓有亮点,就是在这些实现功能的基础上,在以下几个方面做出了探索和优化, 个人能力有限,先聊这几个方面。
- 大数据量优化
- 研发效率的提高
- 研发质量的提高
- 性能优化
- 用户体验优化
- 复杂 & 新场景
- …
我们以大家都做过的需求举例,通过优化,每个需求都可以做成有亮点的需求,也就是所谓企业级的项目。
1、大数据量
想做出亮点,首先做一些你周围同事做不到的需求,首先就是数据量变大,变得贼大,虽然大部分场景遇不到,但是挡不住骚包面试官喜欢问,我们只聊面试。
1.1、课程页面,增删改查
这种场景,我们可以让数据量变成1W行,大部分场景都是分页,只有极端场景(移动端无限滚动的商品页),如果直接渲染1W行列表,不出意外你的页面就要卡了,比较常见的优化方案就是虚拟滚动,就是只渲染你能看到的视窗中的几十行,然后通过监听滚动来更新这几十个dom,大致原理图如下 (网上找的)。
解决方案出来后,无论是Vue还是React解决方案都是类似的,这里用React+Typescript举栗子,首先我们就得完成下面的任务,为了简化场景,先假定每个元素高度都一样。
- 可视区的高度固定 viewHeight (clientHeight);
- 每个列表高度height (固定);
- 可视区域的数据索引start和end (scrollTop / height);
- 基于startIndex计算出offset偏移(scrollTop - (scrollTop % height);
- 渲染数据 & 监听滚动事件
代码大致如下
// 列表容器的domconst container = useRef<HTMLDivElement>(null)// 开始位置const [start, setStart] = useState(0)// 视图中的数据const [visibleData, setVisibleData] = useState<VirtualProps['list']>([])// 控制偏移量const [viewTransfrom, setViewTransfrom] = useState('translate3d(0,0,0)')useEffect(() => {const containerDom = container.currentconst viewHeight = containerDom?.clientHeight || 500 // 视窗高度const visibleCount = Math.ceil(viewHeight / HEIGHT) // 视窗内有几个元素const end = start + visibleCountsetVisibleData(list.slice(start, end))}, [])function handleScroll(e: React.UIEvent<HTMLDivElement, UIEvent>) {const scrollTop = e.currentTarget.scrollTop // 滚动的距离const containerDom = container.currentconst viewHeight = containerDom?.clientHeight || 500 // 视窗高度const start = Math.floor(scrollTop / HEIGHT)const end = start + Math.ceil(viewHeight / HEIGHT)setVisibleData(list.slice(start, end))setStart(start)setViewTransfrom(`translate3d(0,${start * HEIGHT}px,0)`)}
稍微难一丢丢,或者更骚包的面试官还会问,如果每行都是一段文字,不知道有多高呢?其实解决方案也不复杂,可以预估一个大致的高度,然后渲染的时候获取实际dom的高度 + 缓存到数组
下面是伪代码,由于位置数组是一个累加的数组,其实还可以用二分算法继续优化,给博友们留个作业吧。
// 预估高度60
const PREDICT_HEIGHT = 60// 不定高数组,维护一个位置数据
const [positions, setPosition] = useState<{ top: number;height: number }[]>([])// 渲染数组之后,更新positions数组
Array.from(listDom?.children).forEach((node, index) => {const { height } = node.getBoundingClientRect()// console.log(start+index, node.id)if (height !== positions[start + index].height) {setPosition((prev) => {const newPos = [...prev]newPos[start + index].height = heightfor (let k = index + 1; k < prev.length; k++)newPos[k].top = newPos[k - 1].top + newPos[k - 1].heightreturn newPos})}
})
}, [visibleData])
1.2、文件上传
其实就是数据量大了之后,想继续让用户有比较好的交互体验,就得不断地解决新问题
上传普通文件axios.post + 进度条就搞定了,如果想有亮点,可以把文件的体积想的大一些,比如2个G,直接上传容易断,我们需要断点续传,就诞生几个新的问题
- 文件切片 + 秒传 + 暂停
- 文件计算hash值,就像文件的身份证号,用来问后端有没有切片存在
- 计算hash的卡顿 可以使用web-worker,时间切片,抽样Hash三种解决方案
- 上传文件切片
2、研发效率的提高
程序员也是一种很贵的资源,能提高他们的研发效率,也算是给公司省钱了,当然是亮点了,但是每个人的开发能力不同,我们可以从团队协作和多项目间复用两条路,来寻求研发效率的提高
团队效率
最常见的就是统一规范,js规范,git 分支规范,log规范,项目文件规范,并且用恰当的工具进行自动化校验和修正
然后是多项目间的复用率,也能极大地提高效率
- 代码初始化,可以封装成脚手架,类似create-vite, 可以内置上面说的各种规范,新项目直接启动
- 代码研发效率, 前端主要就是组件库和工具库utils封装
- 代码联调效率, 比如接口json自动生成Typescript接口类型等等,比如mock数据工具
- 代码上线效率,发布部署,部署结果同步到聊天群等等,把日常重复的行为自动化
这部分也有大量的开源代码可以参考,比如React生态的AntDesign,Vue生态的Antd-vue和element-ui, vueuse, 通用工具库参考lodash等等,这里就不赘述了
这也是大部分团队能有机会做开源的领域,由于需要多个项目之间的共用,所以对代码质量,版本管理,代码文档也会有更高的要求,无形中也提高了我们的段位和能力
现在很火的rust生态,可以极大地提高前端编译的速度,其实也无形中提高了开发者写代码时候的心情和效率,比如webpack换成vite,babel换成swc,还有现在很火的rspack,都是努力让前端开发环境能有丝滑秒开的体验
还有一些非代码层面的协作效率,比如敏捷看板,高效开会,代码review啥的,不在本篇文章讨论范围之内,先略过
3、研发质量的提高
质量的提高,也是程序员上限的提高
这一部分其实也是一个大话题,【重构】【整洁代码的艺术】【代码大全】等经典书籍数不胜数,不过在前端这个比较蛮荒的领域,能把自动化测试做好,就已经非常难得了
业务性的页面写测试成本过高,但是上面说的多项目之间共享的组件库,工具库还是需要用测试来确保代码质量,学会jest或者vitest写测试,也是我们有机会参与热门开源项目的机会,代码测试覆盖率也是一个项目质量高低的重要指标,而且也是代码可维护性高的体现
你可以现在就尝试用vitest给你项目中写的工具函数 or组件库来点测试代码保驾护航把
除了代码层面的单元测试,还有流程层面的,比如code-review,
4、性能的提高
天下武功,唯快不破
如何让页面打开速度更快是一个永恒的话题,性能优化第一课首先你就得知道页面性能几个常见的指标,FCP,TTI,LCP,就像我们想提高游戏水平,就得了解攻击力防御力这些参数的含义
前端优化可以先从两个方向开始
4.1. 更快的加载文件
首先前端工程化中的打包压缩,就是减少了文件的体积和数量,并且通过很好的文件缓存管理,最大限度的利用浏览器的缓存,达到更快加载文件的目的
文件体积里,其实图片的格式选择和优化是大头,jpg, png, webp的选择,还有打包中图片的压缩,都可以获得比较可观的体积收益,静态资源还可以使用cdn继续提高加载文件的速度
还可以使用懒加载的思想,减少首屏加载的文件数量,也可以很好的提高文件加载的速度,图片/路由懒加载现在在前端开发领域都是必备特性了,快去手写一个lazy-load把
rollup带来的tree-shaking能力(跟互联网公司裁员还挺像,囧),可以去除项目中的无用代码,现在也成了前端工程化的标配,这也是为什么我们要尽量向esm规范靠拢的原因之一,而且静态分析还可以给我们带来一些额外的收益,比如vite中的预打包等等
这些我们都可以在工程化环节使用工具or插件的形式存在,所以学会定制webpack/vite的插件也成为前端架构师的必备能力之一, 快去学起来把
4.2. 代码执行的更快
这里也很好理解,执行的速度也是鉴定代码好坏的一个指标,比如同样一个leftpad函数(前面补齐字符),如果这么写
function leftpad(str,length,ch){let len = length-str.length+1return Array(len).join(ch)+str
}
console.log(leftpad('hello',10,'0'))
相比于我们用二分法+位运算的优化思路的写法
function leftpad2(str,length,ch){let len = length-str.lengthtotal = ''while(true){// if(len%2==1){if(len & 1){total+=ch}if(len==1){return total+str}ch += chlen = len >> 1// len = parseInt(len/2)}
}
console.log(leftpad2('hello',10,'0'))
console.time('leftpad')
for(let i=0;i<10000;i++){leftpad('hello',1000,'0')
}
console.timeEnd('leftpad')console.time('leftpad2')
for(let i=0;i<10000;i++){leftpad2('hello',1000,'0')
}
console.timeEnd('leftpad2')❯ node leftpad.js
00000hello
00000hello
leftpad: 51.97ms
leftpad2: 2.077ms
数据量越大,性能差距就越大,数据量是1W的时候,性能有25倍的差距,当然也可以看出来算法和数据结构对前端的必要性,对不同的场景选择合适的算法or数据结构也是高级前端的必备能力
不同的框架内部也有不同的性能优化方式,减少组件不必要的rerender,减少浏览器的重绘回流,减少页面内部的dom操作等等经典的优化方式 就不赘述了
还有按需执行代码的思想,比如vue3种的静态标记,只有dom种的动态部分需要参与计算diff,静态的dom会直接略过, 还有astro,nuxt3这种ssr框架中的岛屿架构,就是只对页面中的动态组件进行js激活,都是按需思想的表达
5、复杂场景
一些天生复杂的场景,或者是前端新兴的领域或者热门的领域,面试官也比较喜欢,这个方向就比较多了,以后有机会展开详细说说
- 很火的低代码(搭建平台)
- 文档技术 (在线office,notion笔记)
- 图形学(figma,白板,canvas)
- 3D (可视化,游戏,webgl)
- app、桌面端(flutter、rn、elecrton)
- 更多未来的可能性…
6、不要陷入成长陷阱
写了这么多,我们要无限进步,但是不要陷入低水平的成长陷阱中,也就是我们要努力学会通用技能,而不是单纯的招式。
比如以前浏览器混战的时候,我有花了很多时间研究ie6/7/8的兼容性问题,并且感觉自己进步很大,但是浏览器兼容是一个特定混乱时期的问题,现在回头看看,那些兼容性的写法对于现在的我,毫无积累
我们要花更多的时间学习能够对我们有积累效果的技能,现在webpack和vite是工程化领域混乱发展的时期,过于关注api的使用,以后有一个工具统一这个领域后,你现在努力学习的工程化工具技能,跟当年的ie6兼容性一样,都被历史埋了。
可以试着学习webpack和vite内部的原理,学习他们内部优化的思想,怎么收集文件的依赖关系,怎么实现模块化,怎么实现loader和plugin机制扩展自身,怎么实现高效的热更新等等,这些才是能够帮助我们对未来有积累的技能。
少学api,多研究点问题和本质。
相关文章:

面试官:你做过什么有亮点的项目吗?
前言 面试中除了问常见的算法网络基础,和一些八股文手写体之外,经常出现的一个问题就是,你做过什么项目吗? 面试官其实是想看看你做过什么有亮点的项目, 其实大家日常做的项目都差不多,增删改查,登录注册&…...
【华为OD机试真题】猜字谜(javapython)
猜字谜 时间限制:1s空间限制:256MB 限定浯言:不限 题目描述: 小王设计了一个简单的猜字谜游戏,游戏的谜面是一个错误的单词,比如nesw,玩 家需要猜出谜底库中正确的单词。猜中的要求如下: 对于某个谜面和谜底单词,满足下面任一条件都表示猜中: 变换顺序以后一样的,…...

制作真人手办有哪些不便?怎么解决?
相信很多朋友都喜欢拍摄写真,比如孩子生日的时候,结婚纪念的时候,写真照片能留存住很多美好的记忆。 不过随着科技的发展,大家已经不能满足只靠照片来记录生活了,越来越多的人开始盯上了手办这件物品。将真人的照片和…...

网络安全行业现在好混吗,工资水平怎么样?
前段时间看到有人私信:网络安全行业现在好混吗,工资水平怎么样?今天在这里做个回答,不知你所说的“好混吗”指的是什么? 薪资高,待遇好?不加班,活儿少?不受气࿰…...

【SpringBoot】面试组合技-天羽屠龙舞,SpringBootApplication注解的作用是什么?SpringBoot怎么实现自动装配的?
SpringBoot源码下载地址:https://github.com/spring-projects/spring-boot/tags 文章目录🍟下载源码🍗环境准备🍖注解解析🍝SpringBootConfiguration注解🍛EnableAutoConfiguration注解🍤AutoC…...

2023-4-10-用Pthreads计算积分
🍿*★,*:.☆( ̄▽ ̄)/$:*.★* 🍿💥💥💥欢迎来到🤞汤姆🤞的csdn博文💥💥💥💟💟喜欢的朋友可以关注一下࿰…...
什么是js?js的基本使用
JavaScript(简称“ js”) 是一种具有函数优先的轻量级,解释型或即时编译型的编译语言虽然它是作为开发WEB页面的脚本语言而出名,但是它也被用到了很多非浏览器环境中,JavaScript 基于原型编程、多范式的动态脚本语言&a…...
自然数的拆分问题 字典序
目录 自然数的拆分问题 字典序 程序设计 程序分析 自然数的拆分问题 字典序 对于大于1的自然数N,可以拆分成若干个大于等于1的自然数之和。 Input 一个大于1的自然数N Output 所有的拆分情况.按字典序排列。 Sample Input...

软件测试——概念篇
目录 一、软件的生命周期 二、瀑布模型(Waterfall Model) 优点: 缺点: 三、螺旋模型(Spiral Model) 编辑优点: 缺点: 四、增量、迭代 区别: 五、敏捷 scrum…...

Qsort函数的应用与讲解
解释: qsort排序函数,即讲一段数组,字符串等进行有序的排列 分析: void qsort (void* base,//要排序的数组的首元素(就是数组名)size_t num, //要排序的数组元素的个数size_t size,//每个元素的字节大小&…...

蓝桥杯嵌入式第九届客观题解析
文章目录 前言一、题目1二、题目2三、题目3四、题目4五、题目5六、题目6七、题目7八、题目8九、题目910、题目10总结前言 本篇文章为大家带来第九届客观题的讲解。 一、题目1 STM32F103RBT6 微控制器是一款基于 ARM Cortex-M3 内核的单片机,它具有多个外设和总线,包括 APB1…...

多元函数的基本概念——“高等数学”
各位CSDN的uu们你们好呀,今天,小雅兰的内容是多元函数的基本概念,下面,让我们一起进入多元函数的世界吧 平面点集 多元函数的概念 多元函数的极限 多元函数的连续性 有界闭区域上多元连续函数的性质 平面点集 第一个是坐标平…...

LabVIEW-数值控件和布尔控件
简介 LabVIEW 以其强大、开放、图形化的虚拟仪器软件开发环境使得无论是否有过编程经验的工程师或科学家使用它时都可以快速、高效地与测量和控制硬件通信,并进行复杂的数据分析及处理。LabVIEW集成了满足GPIB、PXI、VXI、RS232、RS485、USB、DAQ等多种形式的设备互…...

R730重组阵列raid5
如何进入阵列界面,可以参考这篇文章:R730服务器热插拔换磁盘(raid阵列) 首先来到阵列界面:来到红框Disk Group处,然后按F2 然后移到箭头处,回车(删掉磁盘组) 然后发现…...

Verilog学习笔记3——数据位宽、阻塞/非阻塞赋值、二进制码、独热码、格雷码比较、编写原则、三态门、
文章目录前言一、数据位宽1、有符号定点数2、Nbit和Mbit相加或相乘二、阻塞赋值和非阻塞赋值三、timescale四、三态门的设计五、verilog模块编程原则六、二进制码、独热码、格雷码比较1、独热码2、格雷码3、二进制码前言 2023.4.5 清明节 一、数据位宽 N位有符号数࿱…...
C++ Qt智能指针使用教程
C++ Qt智能指针使用教程 contents 一、 QSharedPointer用法二、 QWeakPointer三、QScopedPointer四、QPointer五、Qt智能指针需要注意的坑Qt提供了类似C++11智能指针的实现,用于自动管理动态分配的内存,避免内存泄漏和悬挂指针等问题。使用智能指针可以使代码更加安全、简洁和…...
【题解】BZOJ4975 区间翻转
题目大意 两人博弈,有一个 nnn 的排列 a1,a2,…,ana_1,a_2,\dots,a_na1,a2,…,an,每次操作为选择长度为 4x24x24x2 或 4x34x34x3 的区间,将其翻转,要求翻转后字典序大于翻转前。第一个不能操作的输。Q 先手,T 后…...

火箭参数相关知识
火箭参数相关 前言:学习笔记,很初级部分内容来之相关书籍,入门学习,欢迎指正 1 坐标系右手定则: 伸开手掌,大拇指指向X轴,四指指向Y轴,四指弯曲90后所指向的方向为Z轴。X 、Y、Z并…...

【JavaEE】死锁是什么?如何避免死锁(保姆级讲解)
博主简介:想进大厂的打工人博主主页:xyk:所属专栏: JavaEE初阶本篇文章将介绍什么是死锁,死锁的四大必要条件,如何去避免死锁~~~ 目录 一、死锁是什么? 二、关于死锁的情况 2.1 一个线程的情况 2.2 两个线程的情况…...
JS 实现占位符截取字符串内容
//charnum占位长度, //str 字符串内容 //返回charnum占位长度 下的字符串长度; function getcharlength(charnum,str){ var len 0; for (var i 0; i < str.length; i) { var c str.charCodeAt(i); //单字节加1 …...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

淘宝扭蛋机小程序系统开发:打造互动性强的购物平台
淘宝扭蛋机小程序系统的开发,旨在打造一个互动性强的购物平台,让用户在购物的同时,能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机,实现旋转、抽拉等动作,增…...

数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !
我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...

rknn toolkit2搭建和推理
安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 ,不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源(最常用) conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...