
2017年秋天我参加了触宝科技的秋季校招笔试岗位是客户端前端批次是第三批。这场笔试说不上是当年最难的一场但绝对是让我最“别扭”的一场——它不像纯后端卷那样全是算法和并发的硬核题也不像纯前端卷那样从头到尾围着浏览器和框架打转而是把客户端、前端、网络、操作系统混在一起考几乎每道题都在问同一件事你写的东西到底是怎么跑起来的。考完那天晚上我在宿舍把能回忆起来的题目按知识点重新整理了一份笔记发现这套卷子的出题思路其实非常清晰它不考八股考的是工程里真正会遇到的取舍。现在把这份复盘整理成文希望能给正在准备客户端类岗位笔试的同学一点参考。1. 为什么2017年触宝第三批笔试到现在还值得翻出来复盘1.1 触宝是谁客户端前端又是什么先把这个岗位本身说清楚。触宝科技以触宝输入法起家后来又做了电话助手之类的工具类产品主要市场在海外。工具类App有一个共同特点功能高度集中每次版本更新都依赖客户端性能、网络策略和页面渲染体验所以它对客户端工程师的要求从来不是“能写界面”就行而是要懂性能、懂网络、懂适配、懂数据上报。“客户端前端”这个叫法在当年不算特别标准它更像是一个复合型岗位既要掌握Android或iOS的原生开发又要具备H5/前端能力甚至包括React Native这类刚兴起的跨端方案。触宝的产品里有大量使用WebView承载的活动页、运营页和内容页原生壳负责稳定H5负责动态更新和快速试错。笔试里出现前端知识并不是出题人顺手加上去的而是这些知识在真实业务里确实会被用到。1.2 “第三批”这三个字里藏着什么信息企业校招分批笔试在2017年已经很普遍。第一批往往是内推、宣讲会现场投递和最早网申的人第二批是常规批次第三批通常是补录、加场或者为了错开其他公司笔试高峰而临时加的场次。第三批有一个非常实际的特点它往往是“调整过难度”的卷子。前两批交卷之后出题人手里已经有了成绩分布能看出哪些题区分度不够哪些考点大家都会哪些题型几乎没人做出来。我自己的感觉是第三批的卷子会更偏向综合考察而不是堆难点。比如第一批可能考了二叉树的层序遍历第三批就可能换角度考二叉树的序列化与反序列化第一批考了经典的进程与线程区别第三批可能把它包装成一个“App为什么有时会卡死”的场景题。所以复盘第三批笔试比复盘第一批更能看出一家公司到底想筛什么样的人——因为它是经过数据验证后的出题思路。1.3 这场笔试对今天的备考还有什么参考意义说实话2017年的技术栈和现在差别很大。那时候Flutter还没有形成气候React Native刚火起来Android面试还在高频问HashMap原理和图片加载框架而现在大家聊的是Compose、Kotlin协程和鸿蒙生态。但笔试的底层逻辑没有变过基础、场景、代码三大块仍然是客户端前端笔试的骨架。这篇文章不会去贴“原题”这种东西——事实上也没有人能保证几年前的题目还会再考。我更想做的是把一套“客户端前端笔试应该怎么准备”的思路拆开讲清楚结合那场笔试里的题型分布给后来人一个可以直接参考的准备框架。2. 整张卷子的结构选择、简答、编程三关分别卡什么人2.1 我在卷子上看到的大致结构先还原一下整场考试的体感。总时长大约两小时题量不算吓人但知识点密度很高。卷子基本是三段式20道左右的单选题覆盖数据结构、操作系统、计算机网络、Java基础还会夹杂几道JavaScript或H5的题3到4道简答题基本是场景题比如“App启动速度慢怎么排查”“WebView加载慢怎么优化”2到3道编程题前一两道是常规算法最后一道往往偏业务逻辑需要根据条件设计状态转换这个结构本身就很能说明问题选择题考知识面简答题考工程判断编程题考代码功底。三道关卡分别筛选不同层级的候选人任何一关有硬伤都会被卡掉。2.2 选择题覆盖广、单题分值低、比的是熟练度选择题的特点是“广而浅”不要求你对某个知识点研究得多深但常见的那些基础点你必须形成肌肉记忆。HashMap的扩容机制、TCP四次挥手的状态变化、进程和线程的区别、Activity生命周期、JS事件循环都是高频面孔。我印象里有一道题是“多线程环境下如何安全地实现单例模式”。表面考Java语法实际上考的是你是否认真想过自己写的代码在并发环境里会发生什么。选饿汉式、懒汉式加synchronized、还是用静态内部类不同写法对应不同性能开销和安全性。这种题没有太多绕弯的地方但如果平时只是背概念、没写过并发代码很容易在几个选项之间犹豫。选择题想拿分没有捷径只能靠刷基础题刷到条件反射。但我建议不要只看正确答案每一道错题都值得把背后知识点展开看一遍因为同一考点在简答题里换件外套又会再出现。2.3 简答题拼答题框架不是拼字数简答题最忌讳的就是“想到什么写什么”。比如问你“如何优化页面首屏加载时间”如果只写“压缩资源、CDN、图片懒加载”只能拿基础分如果写成“先分阶段请求阶段可以做什么、渲染阶段可以做什么、数据返回阶段可以做什么再在每个阶段下面列具体手段”得分会明显不一样。为什么出题人爱这么考因为简答题本质上是在考察你的排查思路。面试官想知道你是拿到问题就上手改还是能够先定位、再动手、最后验证。这个思维习惯在客户端开发里非常重要——线上出现了Bug你不定位到根因就乱改代码只会制造更多问题。所以写简答题时哪怕知道的不多也要把“我会怎么一步步排查”的步骤写出来这比堆砌十个不痛不痒的技术名词有用得多。2.4 编程题区分度最高的部分编程题是整张卷子最拉开差距的地方。它不是“你想不想得出来”的问题而是“你能不能把一道题用最简单、最不容易出错的方式写对”。笔试平台通常只给一个编辑器没有智能提示、没有自动缩进、没有编译器帮你查错。你需要自己处理输入输出自己考虑空值自己保证代码在边界条件下不出错。平时习惯了在IDE里敲代码、靠插件和快捷键辅助的人第一次上笔试平台会非常不适应。这也是为什么我后来一直建议学弟学妹刷题的时候尽量用在线平台别总是开着IDE写。3. 客户端基础题Android、iOS、H5交叉得最狠的那批考点3.1 原生客户端基础部分绕不开的几件事客户端前端的笔试原生部分占比通常最高。翻来覆去考的其实是几件事。生命周期是绝对高频。Android的Activity生命周期、iOS的UIViewController生命周期已经不只是概念题而是会结合场景问来电打断了当前的Activity会发生哪些回调从后台回到前台哪些数据需要恢复如果你不理解系统什么时候会回收页面、什么时候会重建页面就很难答好这类题。事件分发机制也是区分度很高的考点。dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent这三个方法的调用顺序能刷掉一大批只会写setOnClickListener的人。这种题为什么不讲虚的因为当页面出现滑动冲突、点击穿透、列表滚动不跟手时不懂事件分发的人只能靠到处试配置懂的人一眼就能定位问题出在哪个环节。消息循环几乎是必考。Handler、MessageQueue、Looper之间的关系本质上是在问“一个线程为什么需要消息队列”。Android不允许在子线程更新UI这个限制背后就是消息循环机制。理解了这一点你写异步代码的时候才会知道哪个回调跑在哪个线程上。内存泄漏也是选择题和简答题的高频话题。静态变量持有Activity、Handler延迟消息持有外部类、注册了监听没有反注册这些案例在真实项目里反复出现。笔试一般不会让你写出完整的LeakCanary分析报告但会问“下面哪段代码可能导致内存泄漏”或者“请列举三种常见的内存泄漏场景”。3.2 H5与前端基础笔试里被低估的占比客户端前端这个岗位和纯前端不一样它考前端知识不会考框架源码那么深但会考和客户端强相关的部分。浏览器渲染流程是一个重点。HTML解析成DOM树、CSS构建样式规则、布局、绘制、合成这条链路必须能讲清楚。为什么要问这个因为混合开发里大量使用WebView页面白屏多久、滑动会不会掉帧都和这条渲染链路有关。如果你能答出“style变化会引起重绘还是回流”“哪些CSS属性会触发合成层”在笔试里会明显区别于只会写React组件的候选人。JS事件循环也是高频题。宏任务和微任务的执行顺序setTimeout和Promise谁先执行几乎是每逢招聘季必出现的经典题。客户端前端会考这道题是因为H5和原生通信时大量依赖异步回调时序搞错消息就会乱。比如先发起一个JsBridge调用再紧接着发起另一个如果异步处理顺序不对数据回传就可能错位。WebView与原生通信的JSBridge原理属于更高一级的考点。笔试如果出现一般不会让你手写完整实现而是以简答题形式出现问你怎么设计一个安全的通信桥。这题没有标准答案但需要你考虑到协议格式、回调管理、超时处理、URL拦截和原生注入两种方案的优劣以及安全校验。3.3 跨端思维2017年就在考的问题我印象很深的一道简答题大意是在一个Hybrid方案里哪些功能适合用原生实现哪些适合用H5实现这道题表面考技术选型实际考的是跨端思维。原生实现适合交互复杂、依赖系统能力、对性能要求高的场景比如地图、相机、支付H5适合更新频繁、逻辑简单、需要快速试错的场景比如活动页、运营位。没有绝对的好坏核心是在开发效率和用户体验之间找平衡。现在回头看这道题的考察逻辑放在Flutter、RN大行其道的今天依然成立。技术方案一直在变但“判断一个需求发生在哪一端最合适”的思考方式是客户端前端工程师必须具备的基本功。4. 计算机基础题网络与系统是怎么和客户端扯上关系的4.1 网络协议背结论只是及格理解场景才高分网络部分的题集中在TCP/UDP和HTTP/HTTPS上。TCP三次握手、四次挥手是基础但只背状态名没用要能解释为什么挥手需要四次——因为TCP是全双工的通信双方必须分别关闭各自方向上的通道。HTTP部分除了请求方法、状态码和缓存机制我建议重点理解缓存协商过程。客户端开发里图片加载、接口请求、H5静态资源全都依赖HTTP缓存。如果你能说清楚Cache-Control和ETag的配合逻辑在简答题里就多了别人没有的细节。HTTPS握手过程也经常考。这里要注意客户端工程师经常面对“抓包看不到明文”的困惑所以理解证书链校验、对称加密与非对称加密在握手中的分工比单纯背一遍握手流程更有用。另外还有一个客户端特有的网络场景弱网。笔试里可能把它包装成简答题——“弱网环境下你会如何设计一个请求的重试机制”这题考察你对超时时间、连接池、指数退避、请求幂等性的理解。大部分人的答案只会写“设置短超时”但更好的回答是分场景首次请求可以超时短一点失败后重试用指数退避同时要做好请求去重和幂等设计。4.2 操作系统线程、内存、进程通信都是工程问题的底子操作系统在客户端笔试里的出题方式比纯后端要轻但绝不是可以完全忽略的。进程和线程是必考但考法偏场景。比如“为什么App的主线程不能做耗时操作”这个问题表面考线程模型实际是想确认你能不能区分UI线程和子线程的职责边界。耗时操作放在子线程是常识但真正写代码时很多人把网络请求、图片解码、数据解析都塞进主线程最后导致列表滑动卡顿、页面跳转掉帧。线程池的考察也比较常见。核心线程数、最大线程数、队列长度这些参数不能光背而是要理解它们如何影响资源消耗。比如在客户端里开了大量线程去请求图片结果CPU切换上下文的开销比下载本身还大这就是线程池参数没设计好。内存管理方面Java的GC机制、对象引用类型、内存回收算法会出现LRU缓存是高频词Android里的LruCache就是典型应用。操作系统里的页面置换和内存回收逻辑和客户端内存优化在思路上相通建议放在一起理解。4.3 为什么这些基础不能临时抱佛脚原因很简单客户端前端的工程问题几乎都是这些基础知识的组合。“列表滑动卡顿”这个问题拆开来看是“主线程执行了耗时任务”往深挖可能是布局层级过深导致测量和绘制成本高、图片没有按目标尺寸压缩、列表项复用时状态没有清理干净、网络回调回来后直接在主线程做了大量计算。每一层都需要对应的基础知识来支撑定位。没有网络、系统、数据结构这些底子你连问题该从哪一层开始查都不知道。校招笔试的题不会简单到只考概念也不会难到要写论文但如果你对每一块的掌握都停留在“听说过”的层面卷面就会出现满篇都是正确答案的影子、却每一题都选不对的尴尬。5. 手写编程题除了算法本身还有三个隐形扣分点5.1 常见题型与出现频率笔试里的编程题难度通常集中在LeetCode中等偏下水平但时间压力很大。最常见的几类字符串和数组反转字符串、最长无重复子串、合并两个有序数组链表反转链表、检测链表是否有环、找到链表中点二叉树前中后序遍历、最大深度、最近公共祖先动态规划爬楼梯、斐波那契、背包问题的简单变种不需要做到竞赛水平但经典题必须能熟练写出来。我当年准备的时候把这些高频题型反复写了好几遍每次都是限时手写不依赖IDE提示。5.2 边界条件隐形扣分点第一手写代码时第一步不是写主题逻辑而是把所有可能的输入在脑子里过一遍空链表、只有一个节点、数组长度为0、字符串里有空格、数值溢出、负数。笔试平台不像LeetCode那样有详细的测试用例提示很多同学能把主体逻辑写出来却在边界用例上挂掉。比如反转链表很多人写的循环里没有处理“链表为空”的情况直接取next就空指针了。这种失误不是不会做而是习惯没有养好。一个能避开这类问题的小习惯是写完代码后先用三个用例在脑子里跑一遍——最正常的输入、空输入、只有一个元素的输入。这三步只要走完大部分低级错误都能提前发现。5.3 复杂度表达隐形扣分点第二有些同学写完代码就完事全程不提时间复杂度和空间复杂度。这在笔试里很吃亏因为复杂度分析是阅卷人判断你是不是真正理解自己解法的重要依据。比如“两数之和”这道题最容易想到的是两层循环暴力解O(n^2)。如果你写的是哈希表解法并在代码注释里标注“时间复杂度O(n)空间复杂度O(n)”同样是这道题观感完全不同。不要觉得这是形式主义。写注释和复杂度排版的习惯能逼你在写代码之前想清楚自己的算法是不是最优解。如果当场发现有更优做法调整起来也来得及。5.4 代码卷面隐形扣分点第三手写代码和平时用IDE写代码是完全不同的体验。没有自动格式化没有代码补全没有编译器告诉你哪里少了个分号。所以卷面规范要认真对待变量命名要有语义不要全用a、b、c缩进统一关键步骤可以写简短注释但不要写废话如果题目要求从控制台读取输入一定要严格按格式处理输出也精确到空格和换行。我在考场上就吃过这样的亏明明算法思路完全正确但最后输出时多打了一个空格导致判题不通过。后来我把“输入输出格式”当成一道独立的工序来检查每次代码写完先花30秒核对输入怎么读、输出怎么打印再检查算法逻辑。另外建议提前熟悉牛客、赛码这类在线笔试平台的输入输出规范。不同平台对多组输入、字符串读入的处理方式有差异提前练过就不会在考场上浪费时间。6. 从这场笔试回看客户端前端的备考到底该抓哪些主干6.1 按权重分配精力别平均用力如果给备考内容排个优先级我自己的经验是数据结构与算法大约占四成客户端基础占两成半计算机网络和操作系统占两成前端与JavaScript基础占一成半。这个比例不是绝对的但可以避免一个常见误区花大量时间死磕算法到考前发现客户端基础几乎空白。笔试的筛选逻辑决定了算法弱、基础强和算法强、基础弱都可能被挂因为一张卷子每一关都在卡人。更合理的做法是先把基础概念快速过一遍把高频考点整理成清单再用刷算法题的间隙穿插复习清单里的内容。每周末做一次完整的模拟笔试检验这周哪些知识点还不熟。6.2 刷题方法少看答案多逼自己回忆刷题不是看答案这是很多同学最容易踩的坑。打开一道题想了三分钟没有思路马上点开题解看完觉得自己懂了合上又不会。这种“伪刷题”在笔试备考里杀伤力很大。我给自己定过一个规矩一道题在脑子里想二十分钟如果还完全没有头绪才允许看题解。看完题解不算完要把代码全部清掉自己从头写一遍。隔三天再重写一遍直到能独立写对这道题才算真正过去。这个过程中最有效的一点是你会慢慢积累“一眼识别题目类型”的能力。看到一道题先判断它是字符串处理还是动态规划再回忆这类题常用的解法框架。这个判断速度在限时笔试里非常加分。6.3 避坑清单都是别人拿时间换来的教训不要只刷面经题不掌握原理。面经里列出来的考点是结果不是原因要有意识地去看它背后的原理。不要把所有时间都花在算法上。前面说过客户端基础、网络、操作系统在选择题和简答题里的占比很高完全放弃同样过不了。不要忽视简单题的手写练习。中等题想了五分钟觉得会做就跳过容易导致简单题的边界条件都处理不干净。不要等到考场上才第一次用在线笔试平台。牛客、赛码的代码编辑器手感、输入输出格式、本地调试方式至少要提前一周上手适应。6.4 第三批的那张卷子最后教会了我什么现在回头看那场笔试让我印象最深的不是哪道题没做出来而是它让我意识到客户端前端这个岗位考的不是某一个单一维度的能力而是你把知识连成网络的能力。客户端、前端、网络、系统每一块单独拎出来都不是最难的但合在一起出现在卷子里时很多人会发现自己每块都“见过”却每块都说不透。校招笔试的意义恰恰在于把这种“好像会但说不透”的状态暴露出来。备考的时候与其焦虑“我还有多少题没刷”不如先问自己一个问题如果明天考试让我用两句话讲清楚TCP握手、Handler机制、浏览器渲染流程和HashMap扩容各自的原理我能讲清楚吗讲不清楚的地方就是最需要补的地方。