大专前端,三轮面试,终与阿里无缘

120,824 阅读16分钟

因为一些缘故,最近一直在找工作,再加上这个互联网寒冬的大环境,从三月找到六月了,一直没有合适的机会

先说一下背景,目前三年半年经验,base 杭州,大专学历+自考本科

就在前几天,Boss 上收到了阿里某个团队的投递邀请(具体部门就不透露了),因为学历问题,基本上大厂简历都不会通过初筛,但还是抱着破罐子破摔的心态投递给了对方,出乎意料的是简历评估通过了,可能是因为有两个开源项目和一个协同文档加分吧。

进入到面试环节,首先是两道笔试题,算是前置面试:

第一道题目是算法题:

提供了一个数组结构的 data,要求实现一个 query 方法,返回一个新的数组,query 方法内部有 过滤排序分组 等操作,并且支持链式调用,调用最终的 execute 方法返回结果:

const result = query(list)
  .where(item => item.age > 18)
  .sortBy('id')
  .groupBy('name')
  .execute();

console.log(result);

具体实现这里就不贴了,过滤用原生的数组 filter 方法,排序用原生的数组 sort 方法,分组需要手写一下,类似 lodash/groupBy 方法。

过滤和排序实现都比较顺利,在实现分组方法的时候不是很顺利,有点忘记思路了,不过最后还是写出来了,关于链式调用,核心是只需要在每一步的操作最后返回 this 即可。

第二道题目是场景题:

要求用 vue 或者 react 实现一个倒计时抢券组件,页面加载时从 10s 开始倒计时,倒计时结束之后点击按钮请求接口进行抢券,同时更新文案等等功能。因为我对 react 比较熟悉一点,所以这里就选择了 react。

涉及到的知识点有 hook 中对 setTimeout 的封装、异步请求处理、状态更新CSS基本功 的考察等等……

具体实现这里也不贴了,写了一堆自定义 hook,因为平时也在参与 ahooks 的维护工作,ahooks 源码背的滚瓜烂熟,所以直接搬过来了,这道题整体感觉没啥难度,算是比较顺利的。

笔试题整个过程中唯一不顺利的是在线编辑器没有类似 vscode 这样的 自动补全 功能,不管是变量还是保留字,很多单词想不起来怎么拼写,就很尴尬,英文太差是硬伤 :(

笔试过程最后中出现了一点小插曲,因为笔试有时间限制,需要在规定的时间内完成,但是倒计时还没结束,不知道为什么就自动交卷了,不过那个时候已经写的差不多了,功能全部实现了,还剩下卡片的样式没完成,css 还需要完善一下,于是就在 Boss 上跟对方解释了一下,说明了情况。

过了几分钟,对面直接回复笔试过了,然后约了面试。

一面:

  • 自我介绍

    这里大概说了两分钟,介绍了过往工作经历,做过的业务以及技术栈。

  • 七层网络模型、和 DNS 啥的

    计网这方面属于知识盲区了,听到这个问题两眼一黑,思索了一会儿,直接说回答不上来。

  • 然后问了一些 host 相关的东西

    • 很遗憾也没回答上来,尴尬。对方问我是不是计算机专业的,我坦诚的告诉对方是建筑工程。
  • React 代码层的优化可以说一下么?

    • 大概说了 class 组件和 function 组件两种情况,核心是通过减少渲染次数达到优化目的,具体的优化手段有 PureComponentshouldComponentUpdateReact.memoReact.useMemoReact.useCallbackReact.useRef 等等。
  • 说一下 useMemouseCallback 有什么区别

    • 很基础的问题,这里就不展开说了。
  • 说一下 useEffectuseLayoutEffect 有什么区别

    • 很基础的问题,这里就不展开说了。
  • 问了一下 useEffect 对应在 class 中都生命周期怎么写?

    • 很基础的问题,这里就不展开说了。
  • 如果在 if 里面写 useEffect 会有什么表现?

    • 开始没听清楚,误解对方的意思了,以为他说的是在 useEffect 里面写 if 语句,所以胡扯了一堆,后面对方纠正了一下,我才意识到对方在问什么,然后回答了在条件语句里面写 useEffect 控制台会出现报错,因为 hook 的规则就是不能在条件语句或者循环语句里面写,这点在 react 官方文档里面也有提到。
  • 说一下 React 的 Fiber 架构是什么

    • 这里说了一下 Fiber 本质上就是一个对象,是 React 16.8 出现的东西,主要有三层含义:

      1. 作为架构来说,在旧的架构中,Reconciler(协调器)采用递归的方式执行,无法中断,节点数据保存在递归的调用栈中,被称为 Stack Reconciler,stack 就是调用栈;在新的架构中,Reconciler(协调器)是基于 fiber 实现的,节点数据保存在 fiber 中,所以被称为 fiber Reconciler。

      2. 作为静态数据结构来说,每个 fiber 对应一个组件,保存了这个组件的类型对应的 dom 节点信息,这个时候,fiber 节点就是我们所说的虚拟 DOM。

      3. 作为动态工作单元来说,fiber 节点保存了该节点需要更新的状态,以及需要执行的副作用。

      (这里可以参考卡颂老师的《自顶向下学 React 源码》课程)

  • 前面提到,在 if 语句里面写 hook 会报错,你可以用 fiber 架构来解释一下吗?

    • 这里说了一下,因为 fiber 是一个对象,多个 fiber 之间是用链表连接起来的,有一个固定的顺序…… 其实后面还有一些没说完,然后对方听到这里直接打断了,告诉我 OK,这个问题直接过了。
  • 个人方面有什么规划吗?

    • 主要有两个方面,一个是计算机基础需要补补,前面也提到,我不是科班毕业的,计算机底层这方面比起其他人还是比较欠缺的,尤其是计网,另一方面就是英文水平有待提高,也会在将来持续学习。
  • 对未来的技术上有什么规划呢?

    • 主要从业务转型工程化,比如做一些工具链什么的,构建、打包、部署、监控几个大的方向,node 相关的,这些都是我感兴趣的方向,未来都可以去探索,当然了现在也慢慢的在做这些事情,这里顺便提了一嘴,antd 的 script 文件夹里面的文件是我迁移到 esm + ts 的,其中一些逻辑也有重构过,比如收集 css token、生成 contributors 列表、预发布前的一些检查等等…… 所以对 node 这块也有一些了解。
  • 能不能从技术的角度讲一下你工作中负责业务的复杂度?

    • 因为前两份工作中做的是传统的 B 端项目和 C 端项目,并没有什么可以深挖的技术难点,所以这里只说了第三份工作负责的项目,这是一个协同文档,既不算 B 端,也不算 C 端,这是一款企业级的多人协作数据平台,竞品有腾讯文档、飞书文档、语雀、WPS、维卡表格等等。

      协同文档在前端的难点主要有两个方面:

      1. 实时协同编辑的处理:当两个人同时进入一个单元格编辑内容,如果保证两个人看到的视图是同步的?那么这个时候就要提到冲突处理了,冲突处理的解决方案其实已经相对成熟,包括:

        • 编辑锁:当有人在编辑某个文档时,系统会将这个单元格锁定,避免其他人同时编辑,这种方法实现方式最简单,但也会直接影响用户体验。

        • diff-patch:基于 Git 等版本管理类似的思想,对内容进行差异对比、合并等操作,也可以像 Git 那样,在冲突出现时交给用户处理。

        • 最终一致性实现:包括 Operational Transformation(OT)、 Conflict-free replicated data type(CRDT,称为无冲突可复制数据类型)。

      2. 性能问题

        • 众所周知,互联网一线大厂的协同文档工具都是基于 canvas 实现,并且有一套自己的 canvas 渲染引擎,但是我们没有,毕竟团队规模没法跟大厂比,这个项目前端就 2 个人,所以只能用 dom 堆起来(另一个同事已经跑路,现在就剩下我一个人了)。这导致页面卡顿问题非常严重,即使做了虚拟滚动,但是也没有达到很好的优化效果。老板的要求是做到十万量级的数据,但是实际上几千行就非常卡了,根本原因是数据量太大(相当于一张很大的 Excel 表格,里面的每一个单元格都是一个富文本编辑器),渲染任务多,导致内存开销太大。目前没有很好的解决方案,如果需要彻底解决性能问题,那么就需要考虑用 canvas 重写,但是这个基本上不太现实。

        • 因为卡顿的问题,暴露出来另一个问题,状态更新时,视图同步缓慢,所以这时候不得不提到另一个优化策略:乐观更新。乐观更新的思想是,当用户进行交互的时候,先更新视图,然后再向服务端发送请求,如果请求成功,那么什么都不用管,如果请求失败,那么就回滚视图。这样做的好处是,用户体验会好很多,在一些强交互的场景,不会阻塞用户操作,比如抖音的点赞就是这样做的。但是也会带来一些问题,比如:如果用户在编辑某个单元格时,另一个用户也在编辑这个单元格,那么就会出现冲突,这个时候就需要用到前面提到的冲突处理方案了。

  • 可以讲一下你在工作中技术上的建设吗?

    • 这里讲了一下对 hooks 仓库的建设,封装了 100 多个功能 hook业务 hook,把不变的部分隐藏起来,把变化的部分暴露出去,在业务中无脑传参即可,让业务开发更加简单,同时也提高了代码的复用性。然后讲了一下数据流重构之类的 balabala……
  • 你有什么想问我的吗?

    • 问了一下面试结果大概多久能反馈给我,对方说两三天左右,然后就结束了。

结束之后不到 20 分钟,对方就在 Boss 上回复我说面试过了,然后约了二面。

二面:

  • 自我介绍

    • 跟上一轮一样,大概说了两分钟,介绍了过往工作经历,做过的业务以及技术栈。
  • 在 js 中原型链是一个很重要的概念,你能介绍一下它吗?

    • 要介绍原型链,首先要介绍一下原型,原型是什么…… 这块是纯八股,懒得打字了,直接省略吧。
  • object 的原型指向谁?

    • 回答了 null。(我也不知道对不对,瞎说的)
  • 能说一下原型链的查找过程吗?

    • 磕磕绊绊背了一段八股文,这里省略吧。
  • node 的内存管理跟垃圾回收机制有了解过吗?

    • 暗暗窃喜,这个问题问到点子上了,因为两年前被问到过,所以当时专门写了一篇文章,虽然已经过去两年了,但还是背的滚瓜烂熟:

    • 首先分两种情况:V8 将内存分成 新生代空间老生代空间

      • 新生代空间: 用于存活较短的对象

        • 又分成两个空间: from 空间 与 to 空间

        • Scavenge GC 算法: 当 from 空间被占满时,启动 GC 算法

          • 存活的对象从 from space 转移到 to space
          • 清空 from space
          • from space 与 to space 互换
          • 完成一次新生代 GC
      • 老生代空间: 用于存活时间较长的对象

        • 新生代空间 转移到 老生代空间 的条件(这个过程称为对象晋升

          • 经历过一次以上 Scavenge GC 的对象
          • 当 to space 体积超过 25%
        • 标记清除算法:标记存活的对象,未被标记的则被释放

          • 增量标记:小模块标记,在代码执行间隙执,GC 会影响性能
          • 并发标记:不阻塞 js 执行
  • js 中的基础类型和对象类型有什么不一样?

    • 基础类型存储在栈中,对象类型存储在堆中。
  • 看你简历上是用 React,你能简单的介绍一下 hooks 吗?

    • 本质上就是一个纯函数,大概介绍了一下 hooks 的优点,以及 hooks 的使用规则等等。
  • 简单说一下 useEffect 的用法:

    • useEffect 可以代替 class 中的一些生命周期,讲了一下大概用法,然后讲了一下 useEffect 的执行时机,以及 deps 的作用。
  • 说一下 useEffect 的返回值用来做什么?

    • 返回一个函数,用来做清除副作用的工作,比如:清除定时器清除事件监听等等。
  • 你知道 useEffect 第二个参数内部是怎么比较的吗?

    • 说了一下内部是浅比较,源码中用 for 循环配合 Object.is 实现。(感觉这个问题就是在考察有没有读过 React 源码)
  • 前端的话可能跟网络打交道比较多,网络你了解多少呢?

    • 这里直接坦诚的说了一下,网络是我的弱项,前面一面也问到了网络七层模型,没回答出来。
  • 那你回去了解过七层模型吗?我现在再问你一遍,你能回答出来吗?

    • 磕磕绊绊回答出来了。
  • 追问:http 是在哪一层实现的?

    • 应用层。
  • 说一下 getpost 有什么区别?

    • 两眼一黑,脑子一片空白,突然不知道说什么了,挤了半天挤出来一句:get 大多数情况下用来查询,post 大多数情况下用来提交数据。get 的入参拼在 url 上,post 请求的入参在 body 里面。面试官问我还有其它吗?我说想不起来了……
  • 说一下浏览器输入 url 到页面加载的过程:

    • 输入网址发生以下步骤:

      1. 通过 DNS 解析域名的实际 IP 地址
      2. 检查浏览器是否有缓存,命中则直接取本地磁盘的 html,如果没有命中强缓存,则会向服务器发起请求(先进行下一步的 TCP 连接)
      3. 强缓存协商缓存都没有命中,则返回请求结果
      4. 然后与 WEB 服务器通过三次握手建立 TCP 连接。期间会判断一下,若协议是 https 则会做加密,如果不是,则会跳过这一步
      5. 加密完成之后,浏览器发送请求获取页面 html,服务器响应 html,这里的服务器可能是 server、也可能是 cdn
      6. 接下来是浏览器解析 HTML,开始渲染页面
    • 顺便说了渲染页面的过程:

      1. 浏览器会将 HTML 解析成一个 DOM 树,DOM 树的构建过程是一个深度遍历过程:当前节点的所有子节点都构建好后才会去构建当前节点的下一个兄弟节点。
      2. 将 CSS 解析成 CSS Rule Tree(css 规则树)。
      3. 解析完成后,浏览器引擎会根据 DOM 树CSS 规则树来构造 Render Tree。(注意:Render Tree 渲染树并不等同于 DOM 树,因为一些像 Headerdisplay:none 的东西就没必要放在渲染树中了。)
      4. 有了 Render Tree,浏览器已经能知道网页中有哪些节点、各个节点的 CSS 定义以及他们的从属关系。下一步进行 layout,进入布局处理阶段,即计算出每个节点在屏幕中的位置。
      5. 最后一个步骤就是绘制,即遍历 RenderTree,层绘制每个节点。根据计算好的信息绘制整个页面。
    • 渲染完成之后,开始执行其它任务:

      1. dom 操作
      2. ajax 发起的 http 网络请求等等……
      3. 浏览器处理事件循环等异步逻辑等等……
  • 菜单左中右布局,两边定宽,中间自适应,说一下有几种实现方式

    • 比较经典的面试题,说了 flexfloat 两种方式。
  • 项目难点

    • 和一面一样,说了协同文档的两大难点,这里就不重复了。
  • 你有什么想问我的吗?

    • 和一面一样,问了一下面试结果大概多久能反馈给我,对方说两三天左右,然后就结束了。
  • 最后问了期望薪资什么的,然后就结束了。

二面结束之后,大概过了几个小时,在 Boss 上跟对方说了一声,如果没过的话也麻烦跟我说一下,然后这时候,对方在 Boss 上问我,第一学历是不是专科?我说是的,感觉到不太妙的样子,

然后又过了一会儿,对方说定级应该不会高,他后续看一下面试官的反馈如何……

然后又追问我,换工作的核心诉求是涨薪还是能力的提升,这里我回答的比较委婉,其实两个都想要 QAQ

今天已经是第二天了,目前没有下文,看起来二面是过了,但是因为学历不够,中止了三面的流程,基本上是失败了,我也不会报有什么希望了,所以写个面经记录一下。

最后,给自己打个广告!求职求职求职!!!

社交信息:

个人优势:

  • antd 团队成员、ahooks 团队成员,活跃于 github 开源社区,给众多知名大型开源项目提交过 PR,拥有丰富的 React + TS 实战经验
  • 熟悉前端性能优化的实现,例如代码优化、打包优化、资源优化,能结合实际业务场景进行优化
  • 熟悉 webpack / vite 等打包工具的基本配置, 能够对以上工具进行二次封装、基于以上工具搭建通用的开发环境
  • 熟悉 prettier / eslint 基本配置,有良好且严格的编码习惯,唯客户论,实用主义者
  • 熟悉代码开发到上线全流程,对协同开发分支管理项目配置等都有较深刻的最佳实践

可内推的大佬们麻烦联系我!在 github 主页有联系方式,或者直接在掘金私聊我也可,谢谢!!