拼多多前端一面:上传成功率、性能优化与 Promise 手撕
- 轮次
- 一面
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
- 请做一下自我介绍。
- 上传成功率是怎么做的?
- 性能优化是怎么做的?
- 拖拽排序算法怎么实现?
- 手撕:结合 Promise 实现失败重试与超时处理。
- 手撕:扁平化数组,并根据传入数字实现可控次数的扁平化。
- 用 CSS 画图形,说说实现思路。
- 判断事件循环的输出顺序。
《参考解析》
上传成功率:先定义指标——成功上传数除以发起上传数,再按文件大小、网络类型、端类型拆分,避免大文件失败被小文件稀释。实现上用分片上传,每片独立重试并记录进度;文件 hash 做秒传和断点续传,弱网下降低并发、缩短超时;超过重试上限就给出可恢复的失败态。前端还要把网络、超时、服务端拒绝等原因带回埋点。
性能优化:先测量再改,用 LCP、INP、CLS 和长任务定位瓶颈。加载侧做路由级代码分割、图片压缩与响应式尺寸、静态资源长缓存;渲染侧减少首屏依赖、列表虚拟化、避免不必要重渲染;运行时把大计算拆片或放进 Worker。每项优化都要有前后指标对比。
拖拽排序:核心是「指针位置到目标索引,再移动数组」。监听 pointerdown、pointermove、pointerup,拖拽中用 transform 跟随指针,用占位元素腾出落点,根据指针中心与元素中点的关系算目标索引;移动端还要处理滚动容器自动滚边。高频更新用 requestAnimationFrame 节流,拖拽结束只提交一次顺序。
Promise 失败重试与超时:把单次请求包成 runOnce,用 Promise.race([request, timeoutPromise]) 让超时先 reject,并在 finally 里 clearTimeout 防止定时器泄漏。外层循环维护 attempt,捕获错误后判断是否可重试,并给超时错误打标记;重试间隔用指数退避加随机抖动,到上限抛最后一次错误。每次重试都要新建超时 Promise,不能复用已 reject 的那个。
可控深度扁平化:递归写法最直观:depth 小于等于 0 时返回原数组的浅拷贝,否则遍历元素,是数组就递归 depth - 1 并展开,不是就 push。不想递归可以用显式栈存值与剩余深度,避免深层嵌套爆栈。原生 Array.prototype.flat(depth) 默认只降一层且会跳过空位。