ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

小米前端秋招笔试复盘:从JS基础到工程化全考点解析

小米前端秋招笔试复盘:从JS基础到工程化全考点解析 2022年小米秋招前端笔试-卷2我是秋招后半段才做的这套题当时刚被好几家公司的笔试题按在地上摩擦过看到小米这套卷子反而有种“终于正常了”的感觉。题目整体不偏不怪没有那种故意刁难人的脑筋急转弯但覆盖面非常广从JS基础到浏览器原理到框架工程化全都有涉及而且编程题的分值占比不低想靠“背八股”混过去基本不可能。这篇文章我按回忆把卷2的题型结构、核心考点、解题思路和失分重灾区完整复盘一遍如果你是准备投小米前端岗或者正在刷校招笔试题这篇文章可以直接当模拟卷参考来用。1. 笔试整体结构与设计思路1.1 卷2的题型分布与时间分配先说最关心的这套卷子的题型构成。2022年小米秋招前端卷2整体分三大部分限时90分钟总分100分。选择题部分30道每题1.5分共45分覆盖HTML/CSS/JS基础、浏览器原理、网络协议、Vue或React框架基础、前端工程化六个方向。这部分题量很大平均每题只有一分半钟所以拼的是熟练度而不是深度思考。我当时的选择是快速扫描选项遇到一眼能确定的直接过拿不准的先标记做完编程题后如果有时间再回过头来纠结。判断题部分10道每题1分共10分。这10道题是真正拉开差距的地方因为判断题特别喜欢在“绝对化表述”上做文章比如“forEach方法一定会按顺序遍历数组”、“position: fixed的元素一定相对于浏览器窗口定位”这类看着对实际上都有边界情况。编程题部分三道大题共45分。第一道是手写Promise.all第二道是数组与对象的深度处理第三道是场景题设计一个前端大文件上传方案。三道题难度从低到高第一道是送分题第二道是考察代码基本功第三道是考察工程能力和系统设计敏感度没有接触过实际项目的人在这道题上很容易露怯。时间分配上我个人建议选择题控制在30到35分钟判断题控制在5到8分钟剩下50分钟全部留给编程题。编程题里第一道15分钟第二道20分钟第三道15分钟这个节奏比较合理。实际考试中很多人喜欢在选择题上反复纠结结果编程题时间不够这是最亏的。1.2 出题人想考察什么能力分析这套卷子能明显感觉到出题人的几个意图。第一基础扎实度优先。选择题和判断题里大量题目都在考察JS语言本身的细节比如类型转换、作用域、闭包、原型链、this指向、异步执行顺序等。这些内容不依赖任何框架纯看平时积累。很多人觉得这些是“八股文”没用但实际工作中排查bug时最底层的往往就是这些基础概念。第二工程落地能力。三道编程题有两道都是直接的工程场景特别是第三题大文件上传这需要你对后端接口设计、前端文件操作API、上传流程优化都有真实理解。小米这种体量的公司业务里面核心就是效率工具、浏览器应用文件上传是高频场景出这道题是很有针对性的。第三代码风格和边界意识。编程题阅卷时批卷人非常看重三件事函数的健壮性有没有处理异常输入、代码的可读性变量命名和结构、时间空间复杂度有没有明显的性能问题。比如手写Promise.all时很多人漏掉传入空数组、漏掉错误处理、漏掉返回值顺序问题这些细节连在一起分数就拉开了一大截。一句话总结这套卷子考的是一线前端工程师日常真正会用到的东西不是偏题怪题但也别指望靠突击能蒙过去。2. 核心考点逐题拆解与解题思路2.1 JS基础闭包、原型链、异步卷2在JS基础部分出的几道题很有代表性我这里挑几道印象深的来说。有一道题长这样定义一个函数内部声明一个局部变量再返回一个内部函数内部函数引用了这个局部变量然后在外部调用返回的函数两次问输出什么。这其实就是闭包的核心场景。答案是两次调用返回的值都会被内部函数修改因为闭包保存的是变量的引用而不是值。很多人在“闭包保存的是值还是引用”这个问题上栽跟头本质是没想清楚变量和基本类型值在内存中的关系。闭包函数内部的变量只要外部函数执行完毕且返回的函数还活着这个变量就不会被回收这就是闭包能持有状态的原理也是内存泄漏的常见来源。原型链那道题也很有意思给了一段代码function Animal(name) { this.name name; } Animal.prototype.say function() { console.log(this.name); }; function Dog(name) { Animal.call(this, name); } Dog.prototype new Animal(); Dog.prototype.bark function() { console.log(汪汪); }; const dog new Dog(小黑); dog.say();这种题每次笔试都出现考点其实就两个Dog.prototype new Animal() 这行让Dog的实例可以沿着原型链找到Animal.prototype上的say方法Animal.call(this, name)这行让Dog实例拥有自己的name属性。两个缺一不可少了第一个say方法就找不到了少了第二个name属性就是undefined。这里建议彻底理解new的底层原理包括创建对象、设置原型、绑定this、返回对象这四个步骤缺一不可理解了以后所有继承相关的题目都会做。异步执行顺序是每次笔试的必考题。常见的是下面这段setTimeout(function() { console.log(1); }, 0); new Promise(function(resolve) { console.log(2); resolve(); }).then(function() { console.log(3); }); console.log(4);答案是2、4、3、1。原因一句话就能说清Promise构造函数是同步执行的所以立即输出2then里面的回调是微任务在同步代码执行完后立即执行输出3setTimeout的回调是宏任务最后执行输出1。这里很多人错在以为Promise.all里那种then链都是异步的其实只有then/catch/await后面的回调才是异步的new Promise里的执行器函数是同步的。事件循环这块还有一个常见变种把两段async/await代码插进去问输出顺序核心原则依然是微任务优先于宏任务微任务在执行过程中产生的新的微任务会继续在当前宏任务结束后执行直到微任务队列清空。2.2 浏览器与HTTP缓存、事件循环、渲染浏览器原理部分的题目考得最多的是缓存机制和页面渲染流程。缓存那道题给了一张流程图问强缓存和协商缓存的区别以及对应的响应头字段。答案是强缓存直接用本地副本不发请求相关字段是Expires和Cache-Control协商缓存需要向服务器发请求服务器通过If-Modified-Since/If-None-Match来确认资源有没有更新没更新返回304更新了就返回200和新的资源。这里容易丢分的是Cache-Control的几个配置public、private、no-cache、no-store四个值的作用要分清楚特别是no-cache和no-store前者是允许缓存但要先去服务器确认是否新鲜后者是根本就不许缓存。事件循环在卷2里换了个考法它在选择题里问如果页面上有100个节点需要更新用requestAnimationFrame和setTimeout分别驱动哪个更平滑答案当然是requestAnimationFrame因为它由浏览器内部的刷新机制驱动能保证回调在每一帧的开始阶段执行不会丢帧也不会重复执行而setTimeout的节流效果不稳定容易在屏幕刷新周期的中间执行导致视觉上的卡顿。这个知识点平时写业务可能感知不强但做动画、游戏引擎、数据可视化的同学会很敏感。渲染流程那题问的是从输入URL到页面展示的完整过程。这个题属于经典的“背多分”题但卷2稍微变了变它问的是“在哪个阶段会执行JavaScript解析”以及“DOMContentLoaded事件在哪个阶段触发”。这两个点很容易混淆。HTML解析过程中遇到script标签会暂停解析执行JavaScript如果是设置了async或defer的脚本行为又各不相同async是下载完就立即执行不考虑DOM是否解析完defer是等整个HTML解析完再执行。所以DOMContentLoaded事件触发时defer的脚本已经执行完了async的脚本则不一定。还有一道关于localStorage和sessionStorage的题目问这两个存储方案的区别。答案很直接生命周期不同localStorage只要不手动清除就永久保留sessionStorage在关闭标签页后就会销毁作用域不同sessionStorage只在当前标签页内有效localStorage在同一个域名下的所有标签页之间共享。面试或笔试里如果扩展问你为什么不用cookie存用户信息还需要补充cookie每发送一次请求就会自动携带造成不必要的流量开销和安全隐患而Web Storage的数据不会自动随请求发送。2.3 CSS与布局BFC、Flex、GridCSS部分的题目2022年这种节点上Flex布局已经开始普及但Grid还没有完全占主流卷2里两个都考了。BFC那道题主要考察触发条件和作用。常见触发条件有根元素html、float不为none、position为absolute或fixed、display为inline-block/table-cell/flex/grid等、overflow不为visible。BFC的作用用一句话总结就是让元素形成独立的布局上下文内部元素怎么折腾都影响不了外部。三个经典应用要记住解决外边距塌陷、解决浮动元素父容器高度塌陷、阻止元素被浮动元素覆盖。遇到那种“如何清除浮动”的题目除了清空浮动的overflow:hidden原理是触发BFC之外还可以用伪元素clearfix方案后者不会因为影响其他布局特性而出问题。Flex布局那题出了一个经典场景一个容器里有三个子元素第一个希望固定在宽度100px第二个希望占满剩余空间第三个希望宽度固定150px。最合理的做法就是用flex属性控制第二个子元素设置flex: 1其实等同于flex: 1 1 0%意思是按比例扩张、可以收缩、初始大小为0。很多人在这里写flex: 1 1 auto虽然也能用但行为有细微差别auto会让子项先按自身内容宽度占据空间再分配剩余空间导致有时出现内容挤压效果不一致的问题。笔试时建议写成flex: 1更简洁如果面试官深挖再逐步展开。Grid布局的考点是问常见的页面骨架布局方案比如“左侧边栏固定宽度右侧内容区自适应”这种用Grid怎么写。答案很简单.container { display: grid; grid-template-columns: 240px 1fr; grid-template-rows: 60px 1fr 60px; grid-template-areas: header header sidebar main footer footer; }这种写法比Flex更直观因为区域划分是一目了然的。但实际工程中选哪种要看具体场景Flex更适合一维排列Grid更适合二维布局。校招笔试里能写对就行但如果笔试之后有面试建议能说出两种方案在响应式处理上的差异这个加分项很值钱。CSS还有一个老考点是选择器优先级卷2里出了一道计算题。优先级排序是!important最高然后是内联样式接着是ID选择器然后是类选择器/属性选择器/伪类选择器然后是元素选择器/伪元素选择器最后是通配符和继承样式。计算方式用(a, b, c, d)这种四元组来算也行但笔试里通常只要记住ID选择器比一百个类选择器优先级都高这一条就够了。2.4 框架与工程化Vue/React、构建工具框架部分小米的卷子给的是二选一我记得卷子里明确说明可以选Vue方向或React方向的题目作答我当时选的是Vue。Vue部分的题目集中在数据响应式原理。这是Vue面试的核心没有之一。题目问的是修改一个Vue实例的data属性时页面是如何自动更新的。答案主线是Vue把data对象中的每个属性通过Object.defineProperty改造成带getter和setter的形式同时在组件渲染过程中通过getter收集依赖当setter被触发时通知对应依赖更新然后进入异步队列在下一个tick批量更新DOM。这里两个关键点是依赖收集和异步更新队列。很多人只背了“双向绑定”这个名词没有理解Observer、Dep、Watcher三者之间的关系遇到问细节的题就露馅。React方向如果选了常考的会是setState是同步还是异步的问题以及虚拟DOM和diff算法的基本流程。这里有一条非常重要的结论在React18之前的版本中React事件处理函数里的setState是异步批处理的在原生事件和setTimeout里是同步的React18之后引入了自动批处理所有场景都会合并更新。2022年的笔试题大概率还是按React17及以前的逻辑来出的但如果按React18答会更有前瞻性只是阅卷人是否接受不确定建议答题时按版本说明清楚。工程化部分的考点是webpack和Vite的区别。题目问为什么Vite开发模式比webpack快那么多答案核心是webpack在启动时就要分析整个依赖图把各个模块打包成bundle项目越大启动越慢Vite开发模式利用浏览器原生ES Module能力启动时只需要先把入口文件对应的模块关系理出来然后按需编译浏览器请求哪个模块就编译哪个模块所以冷启动速度非常快。这个题在2022年已经算热点了放到现在则是前端简历上必须能说清的基本概念。工程化还有一道关于模块化规范的题考CommonJS和ES Module的区别。CommonJS是同步加载运行时确定依赖关系输出的是一个值的拷贝ES Module是静态编译支持tree-shaking输出的是值的引用。这里“值拷贝”和“值引用”是很多人容易忽略的细节笔试里如果出“在CommonJS中修改模块内导出对象里的属性外部能感知吗”这种题答案是能因为拷贝的是对象引用浅层属性仍然是共享的同一块内存但如果重新给module.exports赋值外部拿到的是旧引用感知不到变化。3. 编程题实战解析3.1 手写Promise.all第一道编程题是手写一个Promise.all要求不能用原生的Promise.all必须自行实现。这道题的考点非常明确对Promise内部机制的掌握程度。很多人第一反应是循环调用传入的Promise数组再用一个计数器判断是不是所有Promise都完成了。这个思路没问题但有一个明显的坑如果直接写成同步循环然后每个.then回调里去累加结果那么当参数里存在非Promise值时需要先用Promise.resolve把它包一层。还有结果数组的下标不能用push必须按下标原样保存才能保持输出顺序和输入顺序一致。一个比较稳妥的实现function myPromiseAll(promises) { return new Promise((resolve, reject) { if (!Array.isArray(promises)) { return reject(new TypeError(argument must be an array)); } const results []; let count 0; if (promises.length 0) { return resolve(results); } promises.forEach((item, index) { Promise.resolve(item).then( (value) { results[index] value; count; if (count promises.length) { resolve(results); } }, (reason) { reject(reason); } ); }); }); }这里有几个细节值得注意。第一空数组的处理Promise.all([])应该返回一个resolve的空数组很多手写实现漏掉这个边界条件。第二reject之后的逻辑不能继续执行所以只写一个reject调用即可不要在后面再做count之类的操作。第三入参校验如果传入的不是数组应该reject一个TypeError。我当年做这道题的时候还额外写了一行console.log来验证结果顺序这种“自测习惯”在笔试中很加分因为阅卷人可以看到你有意识去验证自己的代码是否正确。3.2 实现防抖与节流第二道编程题更偏向实际开发要求实现防抖和节流两个函数题目用例里要求防抖可以传immediate参数节流支持传leading参数。防抖的核心原理是事件触发后不立即执行而是等一段时间如果在这段时间内再次触发就重新计时。所以实现上需要存一个timer每次触发时先clearTimeout再重新setTimeout。function debounce(fn, wait, immediate) { let timer null; let isInvoked false; return function(...args) { const context this; const later () { timer null; if (!immediate) { fn.apply(context, args); } }; const callNow immediate !timer; clearTimeout(timer); timer setTimeout(later, wait); if (callNow) { fn.apply(context, args); } }; }注意这里的callNow逻辑immediate模式下第一次触发时timer是null所以callNow为true立即执行后续触发时timer有值callNow为false只重置定时器。但这里有个细节一次事件循环里如果连续触发多次第一次执行后timer不是null所以不会重复执行只有当最后一次触发后wait时间过了timer被置为null下一次触发才会再次立即执行。这个逻辑初学者容易绕晕建议多看几遍。节流的实现稍简单核心思路是如果距离上次执行的时间小于wait说明还没到执行时机就标记一个pending如果超过了wait就立即执行并更新时间戳。function throttle(fn, wait, leading true) { let timer null; let lastTime 0; return function(...args) { const context this; const now Date.now(); if (!leading now - lastTime wait) { return; } if (now - lastTime wait) { if (timer) { clearTimeout(timer); timer null; } fn.apply(context, args); lastTime now; return; } if (!timer) { timer setTimeout(() { timer null; lastTime Date.now(); fn.apply(context, args); }, wait - (now - lastTime)); } }; }这里用lastTime记录上次执行时间用timer记录是否在等待定时器。如果不处理最后一个等待状态会导致最后一次触发丢失这在滚动监听、resize监听场景中是致命问题。笔试时能把leading和trailing两个模式都考虑到的考生明显是真正写过相关功能的。3.3 深拷贝与数组去重卷2里还有一道题是深拷贝这个题实际上已经把数组去重融合进去了要求拷贝一个嵌套对象并且对象里有一个数组属性需要同时处理。深拷贝一旦考手写就必须要讨论几种边界情况循环引用、Date/RegExp等特殊对象、函数属性、Symbol属性。笔试场景下通常不会要求处理所有边界但至少要能处理循环引用和普通对象数组的基本深度拷贝。一个合格的深拷贝代码如下function deepClone(target, map new WeakMap()) { if (target null || typeof target ! object) { return target; } if (target instanceof Date) { return new Date(target); } if (target instanceof RegExp) { return new RegExp(target.source, target.flags); } if (map.has(target)) { return map.get(target); } const cloneTarget Array.isArray(target) ? [] : {}; map.set(target, cloneTarget); for (const key of Reflect.ownKeys(target)) { cloneTarget[key] deepClone(target[key], map); } return cloneTarget; }WeakMap在这里的作用是保存“原对象 - 克隆对象”的映射遇到循环引用时直接返回已克隆的版本不会死循环。选择WeakMap而不是Map的原因是WeakMap的键是弱引用不会阻止原对象被垃圾回收而且深拷贝完成后这个map本身也不会造成内存泄漏。深拷贝笔试时另一个容易丢分的地方是只处理了对象类型的浅层拷贝。比如直接返回 {...target}这只能拷贝一层嵌套对象和数组还是引用关系改嵌套对象会把原对象也改了。这个考点几乎每次笔试都会考实际项目中也确实是高频bug来源值得重视。3.4 场景题前端大文件上传方案最后一题是场景设计题请设计一个前端的文件上传方案要求支持1GB以上的大文件并考虑断点续传场景。这道题是整个卷子里最能拉开分数的一道。我当年是这么分的。第一部分先说明为什么不能直接用form data提交大文件浏览器和服务器对单次请求体大小有限制上传过程中任何网络波动都可能导致整个请求失败而且没有进度反馈、无法取消、无法断点续传。第二部分既然要支持大文件和断点续传核心方案就是分片上传。前端用File对象的slice方法把大文件切成若干小块比如每片5MB然后逐片上传。上传前先向后端发送一个“创建上传任务”的请求拿到一个唯一的uploadId后续所有分片都带这个uploadId。后端等所有分片上传完成后发送“合并分片”的请求后端按顺序拼接。第三部分断点续传需要支持查询已上传分片前端把uploadId发过去后端返回一个已上传分片编号列表前端跳过这些分片只上传缺失的片段。还有一些细节要提每片并发数要控制避免同时发太多请求把带宽打满上传失败要支持重试针对网络错误做3次以内的指数退避重试上传过程中要实时更新进度条进度按已上传分片数除以总分片数来计算。另外还建议用web worker处理分片和哈希计算避免切片时阻塞主线程不过笔试里提这个概念就能加分。这个题想考察的本质是你有没有做过真实的业务功能而不是只会写UI组件。能想到分片、断点续传、并发控制、进度展示这四个模块已经能超过大部分应试者如果还能提出用hash值做文件秒传验证计算文件的哈希和服务端已有的文件哈希对比一致就直接跳过上传那就是妥妥的加分项。4. 常见失分点与避坑指南4.1 选择题里容易踩的坑第一是JavaScript类型转换的题目。比如[]转换为布尔值的结果是什么答案不是false任何对象包括空数组、空对象转布尔值都是true。再比如null undefined结果是true但null undefined结果是false。这些如果平时没有细看考试时很容易凭直觉判断出错。第二是和的规则卷2里有一道题考了[] ![]的结果。乍看很绕但其实规则很简单![]先把右侧转成布尔值空数组转true再取反所以右侧是false然后[] false进行严格比较前需要把双方转成数字空数组先转成字符串是空字符串空字符串转数字是0false转数字也是0所以结果是true。这种题不是考奇技淫巧是考你对ES规范中ToPrimitive和ToNumber的理解一旦掌握规则遇到任何变种都能稳赢。第三是字体相关CSSem和rem的区别。em是相对父元素字体大小rem是相对根元素字体大小。实际开发中rem配合html的font-size做响应式布局很常用em做局部模块的尺寸缩放很实用。笔试时如果考rem的兼容性处理提到动态换算和postcss-pxtorem插件就够了。第四是关于position: fixed的边界。固定定位元素不一定总相对于浏览器窗口定位如果祖先元素有transform、perspective或filter属性fixed会相对于该祖先元素定位。这个知识点在2022年的卷子里也出现过放在今天依然是高频考点因为CSS动画太常用了transform在页面里几乎无处不在。4.2 编程题里最隐秘的几个扣分点手写Promise.all这题最大的坑是传入的不是数组而是类数组对象比如arguments。很多人觉得for循环能遍历就行可Promise.all的规范要求参数必须是iterable对象而不一定非要数组。所以最稳妥的写法是先用Array.from把类数组转成真数组或者直接在外面加上一个Array.isArray判断。卷2里没要求扩展支持类数组但如果你能主动提到阅卷人会认为你读过规范。深拷贝题有个容易忽略的点是数组中的稀疏空位。比如const arr [1, , 3]如果用for...in遍历只会遍历到下标0和2如果用数组的map方法空位会被保留且回调不会被触发如果直接展开后拷贝空位可能会被还原成undefined。笔试中不用处理得这么细但如果阅卷人看到你用了Array.isArray判断并区分对象与数组就已经比多数人强了。防抖节流题里最容易扣分的是this指向丢失问题。因为返回的是一个新的函数且内部通过fn.apply(context, args)来调用如果忘了把this存下来直接调fn的话在事件监听场景下内部this就会变成window。另一个常见的坑是immediate模式下第一次触发执行之后如果wait时间内又触发了多次最后一次触发时间超过wait后并不会再次立即执行而是进入等待状态需要理解这个行为是否符合预期。场景题最容易踩的坑是“只给方案不给降级策略”。比如你设计分片上传面试官会追问如果后端不支持合并分片怎么办如果用户上传到一半关闭浏览器怎么办如果没有前端计算hash的能力怎么办方案里至少要给出一到两个备选策略说明自己知道这些边界情况而不是把方案当成万能药。4.3 从阅卷视角看什么样的答案能拿高分我在模拟批改这套卷子的时候会把编程题分成三个档次。第一档能跑通基本用例但代码写得比较乱、没有考虑异常输入给60%到70%的分。第二档代码结构清晰、有注释、处理了主要边界条件给80%左右。第三档在第一档和第二档的基础上还考虑到了性能优化、内存管理或工程可扩展性给90%以上。举个例子深拷贝如果只处理了普通对象和数组我给75分加分项是额外处理了Date和RegExp再加一个循环引用检测就能到85分以上。大文件上传方案如果只写了分片和断点续传我给80分如果还提到了并发限制、进度条、秒传、失败重试能拿到90分以上。所以笔试的编程题不是“写完就完事”而是在有限的篇幅里尽可能展示你平时的工程积累。阅卷人还有一个很实用的关注点变量命名。现在很多同学刷题时习惯用a、b、c这种简写在LeetCode上无伤大雅但在企业笔试里代码是要给人看的变量名和函数的职责越清晰越容易拿分。比如上面深拷贝代码中的cloneTarget和map只要看一眼名字就知道它们在干什么这就是好代码。5. 这套卷子之外的备考建议5.1 按这套卷子的节奏安排复习如果你正在准备小米或者类似体量的前端校招建议把复习重点放在JS语言本身和浏览器原理上。我在刷完卷2之后复盘了一遍自己的知识体系发现最薄弱的地方不是CSS也不是框架而是JavaScript异步编程和浏览器缓存机制这两个方向在选择题里的占比非常高而且和实际开发强相关。时间安排上如果还有两周到一个月建议按这个比例分配JS基础占35%浏览器和网络占25%框架和工程化占20%CSS和HTML占15%算法与数据结构占5%。不要花太多时间在复杂算法上前端笔试常考的算法基本就停留在地图遍历、字符串处理、排序、双指针这个级别真正区分度大的是基础细节的掌握度和场景设计题的工程思维。5.2 做题之后的复盘方法做完一套笔试题很多同学的对答案方式就是看一眼正确答案然后自我感觉“哦原来是这样”。这种复盘效率极低。更好的做法是把每道错题当成一个知识节点往深处挖三层。比如缓存机制考砸了至少要重新梳理一遍强缓存和协商缓存的完整流程然后去network面板里看一眼实际页面资源加载时的request headers和response headers确认Cache-Control和ETag是怎么用的最好再用代码实验一下304是怎么触发的。这样一次复盘比刷十道题都管用。5.3 笔试通过后面试会怎么延伸小米的校招笔试通过之后面试环节大概率会针对笔试卷子里的内容做延伸。比如你在大文件上传里写了分片和断点续传面试官会追问切片大小怎么选5MB是拍脑袋还是有依据答不上来就会被比下去。合理的回答思路是切片大小要综合网络带宽、服务器接收能力和内存占用小的切片有利于更细粒度的断点续传但请求次数增多增加服务端压力大的切片传输效率高但断点续传的粒度变粗。一般推荐1MB到10MB之间具体要看场景2G场景下文件和带宽较好可以用8MB或10MB弱网环境用1MB或2MB更稳妥。能说出这个权衡逻辑比背出“5MB”这个数字要专业得多。面试官还喜欢问分片上传如果最后一个分片没传完服务端怎么处理答案是服务端应该维护一个分片状态表每个uploadId对应一个分片列表缺失的分片要返回给前端去补充所有分片齐了才能触发合并接口。如果刚好问到并发控制还要补充前端用p-limit或者手动实现一个简单的并发池把并发数控制在3到5个比较合理。尾声个人实操体会这套卷子我前前后后复盘了三次每次都能从里面挖出新的知识点。2022年做的时候我在大文件上传这道题上想得很浅只写了个“分片上传”四个字后来在项目里真正实现了文本编辑器附件的分片上传遇到了浏览器主线程卡顿、分片顺序错乱、断点续传后文件损坏等各种问题再回来看这道题才明白出题人想让我们关注的点到底是什么。前端笔试说到底不是靠背题能过关的而是靠平时写代码时多问一句“这个方案为什么这么做”把原理真正吃到脑子里。如果你正在刷这套卷子建议把选择题里每一个犹豫过的选项都当成一次深挖知识的机会编程题每道都亲手写一遍并跑通做到这一步你收获的就不只是一份笔试经验而是一个更扎实的前端知识体系。
返回列表