前言

相信很多人都会有一个进大厂的梦吧,这篇文章来讲讲阿里淘系前端的“梦”。一共是5面+HR面,结尾会单独说对于未来前端展望。一次好的面试同时也是进步的契机,能够发掘你一些似懂非懂的问题,让你去深入挖掘,还能将你的痛点暴露出来,面试下来是收获满满的。

一面

这一面主要问了基础部分, 一部分题目我会带上提示
  • TCP 三次握手/四次挥手/等待2MSL意义/建立连接但客户端故障
  • TCP 慢启动/拥塞控制, 快速重传/快速恢复
  • TCP UDP QUIC(QUIC是Http3的底层协议)
  • Http2相对于Http1.1新增了哪些东西, 主要是信道复用之类的
  • 浏览器渲染过程, 注意只是渲染过程, 就是从解析DOM树展示在屏幕这个过程

    主要是 令牌化/建树/收集样式表/布局渲染树/绘制列表/栅格化/绘制图块/...这些过程, 推荐阅读浏览器的工作原理:新式网络浏览器幕后揭秘

  • 强缓存与协商缓存, 主要讲了下E-TagLast-Modified以及对应的标识, 强缓存方案与协商缓存方案的场景, 比如index.html该用哪个?
  • CSS的水平居中与垂直居中
  • 移动端1px, 老问题啦
  • Git操作, 主要是revert与reset, 我们工作室使用的是Git Flow, 并且区分Master和Dev分支这种, 小哥说了一个Git Flow无法handle的场景, 即一个feature还未合并到Master, 但是后面的一个feature已经通过提测要并进主干, 这时要如何处理?
  • React: 新旧生命周期的问题, 为什么要废弃旧版的(约束开发者以及Fiber架构可能会将其打断), 新版的有什么特点(getDerivedStateFromProps(nextProps, prevState), 这个方法是静态方法, 也就说你无法在里面获取到this, 还有就是入参为prevState, 这样就保证stateprops之间更隔离). 还有就是我觉得很好玩的getDerivedStateFromErrorscomponentDidCatch的协作.
  • React: PureComponent, 浅比较, 放一下shouldComponentUpdateshallowEuqal的源码:

      const hasOwn = Object.prototype.hasOwnProperty;
    
      function is(x, y) {
        if (x === y) {
          return x !== 0 || y !== 0 || 1 / x === 1 / y;
        } else {
          return x !== x && y !== y;
        }
      }
    
      export default function shallowEqual(objA, objB) {
        if (is(objA, objB)) return true;
        if (
          typeof objA !== "object" ||
          objA === null ||
          typeof objB !== "object" ||
          objB === null
        ) {
          return false;
        }
    
        const keysA = Object.keys(objA);
        const keysB = Object.keys(objB);
    
        if (keysA.length !== keysB.length) return false;
    
        for (let i = 0; i < keysA.length; i++) {
          if (!hasOwn.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) {
            return false;
          }
        }
        return true;
      }
    复制代码
  • React: setState之后发生的.
    多次setState的合并与获取最新的state, 其实这俩个是同一处代码(好像是particalState), 内部对参数的Object类型和Function类型做了不同的处理, 为函数的情况下, 会在setState调用完成并且组件开始rerender的时候被调用.
  • Node: stream和Buffer, 面试前不久刚写过流式的文件上传所以记忆犹新, 回答了四种流(可写/可读/可写可读/可转换), 以及常用的几个pipe方法

    Buffer的话主要提了一下它是堆外内存(V8的常驻内存由代码区/栈/堆/堆外内存组成)啥的.

  • Node: 内存管理, 这个有看到过通过启动命令更改堆内存上限的文章所以了解的多了一下, 主要关键词有 新生代/老生代假说, Scavenge算法(采用复制实现内存回收, 典型的牺牲空间换时间), From/To空间, 标记清除, 标记整理, 增量标记(将标记阶段拆分为控制在5ms内的小步骤, 每隔一段时间执行, 提高程序流畅性.)

二面

  • 微信小程序, 这个是二面的重点提问之一, 包括以下几个方面:

    • 生命周期, 包括应用级的页面级
    • 架构, View - Native - JavaScript的层级, 系统层能力, 如微信开放能力/离线存储/网络请求等. 视图层的话, 安卓下是腾讯自主研发的基于Blink的X5内核, IOS的话则是自带的WebKit-Webview
    • 使用async/await, 小程序目前好像并不能原生支持async/await语法, 需要引入FB的Regenerator库. 说到这个, 我很好奇Taro/Remax这些方案中是如何处理async/await的, 降级为Promise吗?
    • 鉴权, code2session这个api, 使用sessionKey生成token, openid作为主键入数据库, 再返回自定义的登录态标识
    • H5/RN/Flutter/PWA 这些差异, 主要是和 H5/PWA , 我其实不太认同 PWA是小程序祖师爷 这种说法, 甚至认为不是一个性质, 只是他们的目的/玩法是相似的
    • WXS, 当时小程序也用到了, 主要特点就是运行在View层的逻辑, 并且由于JavaScript在IOS下运行在JSCore, 安卓下运行在V8的原因, 在IOS上WXS可以达到JS数十倍的性能, 但在安卓上和JS持平.
    • setState, 很神奇的一点: 数据改变同步而视图更新异步, 主要也是因为上面提到的架构的原因. 有兴趣的可以再查阅相关资料
    • 小程序如何做到禁止访问Dom, 我的理解是小程序压根就没提供DOM/BOM的API, 并且在打包编译的JS里也获取不到Window对象
  • @Penumbra/cli, 一个思路类似Feflow的脚手架, 也是 脚手架核心+模板插件包+构建器 的一个组合, 模板插件包的话, 前端包含 Webpack/Parcel + TypeScript/JavaScript的组合, 后端包含Koa/Egg + RESTFul/GraphQL的组合. 主要问了这些问题:

    • 为什么要整这个东西, 解决了哪些问题?
    • 带来了什么好处?
    • 为什么还添加了Parcel
  • Parcel和Webpack
  • 错误监控, 我们目前使用的方式是Sentry以及Release时上传Source-Map文件的方式. 自己实现的话, React的思路主要是一个最外层的<ErrorBoundry />组件, 借助getDerivedStateFromErrorcomponentDidCatch来捕获错误.
  • Https加密机制
  • Git Rebase 与 Git Merge
  • Flutter 与 React Native底层
  • Serverless, 这一块可以讲FaaS以及BaaS, 还有Serverless对前端意义, 这个问题千人千面, 就不展开来讲了.

三面&四面

三面和四面发问的角度和提出的问题比较类似, 因此就放在一起讲了.

  • 介绍项目, 通常会问面试官是对业务型项目还是设施型项目比较感兴趣, 业务型的话就介绍小程序, 设施型就介绍@Penumbra/cli

    不要东扯一点西扯一点, 以 技术栈 -> 业务场景 -> 亮点 -> 难点 -> 提炼总结 -> 自我提升 这几个步骤来叙述会更加条理清晰, 其中亮点/难点以STAR法则介绍最佳

  • @Penumbra/cli这个, 上面已经介绍过, 就不再赘述. 主要为了体现 新工程目录建立繁琐 -> 应当成员之间统一目录结构 这个意识
  • GraphQL, 主要介绍了这些:

    • GraphQL的意义, 与RESTFul的差异
    • 对后端的影响
    • Apollo生态, 在这里我想大胆猜测下, 未来的BFF层一定少不了这三个东西: Apollo-Server & TypeGraphQL & Apollo-Rest-Datasource, 至于它们是什么感兴趣同学可以去查查. Apollo不仅提供了服务端支持, 也提供了客户端支持, 即Apollo-Client, 同时使用ServerClient来构建应用真的能起到1+1>2的效果, 因为二者就像是一体的
    • 推广阻力, 其实只要一个团队比较年轻就没有什么阻力, 主要是可能有一定的学习/开发/维护成本~ 嚷嚷着"学不动了"在前端世界里可能真的寸步难行
  • Webpack性能调优, 从 打包速率 / 打包大小 / 交互友好 三个方面入手的, 这里可以稍微列举一些我觉得比较好用/有趣的Plugin:

    • friendly-errors-webpack-plugin, 主要是对抛出的错误做了界面优化, 很多cli都在用
    • speed-measure-webpack-plugin, 测量各个环节的打包耗时, 也可以找出哪一个loader/plugin耗时最久
    • terser-webpack-plugin, 压缩JS
    • webpack-bundle-analyzer, 分析打包产物
    • webpack-visualizer-plugin, 同样是分析打包产物, 但是更直观
    • webpack-parallel-uglify-plugin, 并行压缩, 好像和terser功能重复了
    • webpackbar, 强烈推荐! 在打包时会有进度条(VuePress就用的这个)
    • preload-webpack-plugin, 预加载
  • 至于从配置入手的话, 主要是减少查找文件时间减少build代码体积, 前者可以通过resolve字段中配置extension, loader中配置exclude, 后者的话则主要是Tree-Shaking(注意, CSS也可以做摇树优化), 代码分割(动态加载以及Lodash/Antd这种庞大的模块), Source-Map模式, 压缩代码等等.
  • React函数式组件
  • React Hooks:

    • useState
    • useEffect, 不传dep与传入[], 分别对标类组件的哪个生命周期.
    • useLayoutEffect
    • useRef, 还有useImperativeHandleforwardRef

      • useRef,使函数式组件也能够享受到获取 DOM 元素或者自定义组件,父组件获取子组件引用而后调用子组件方法,如 focus 等
      • forwardRef,可以获取父组件的 ref 实例作为子组件的参数(与 props 同级),然后再把这个 ref 绑定到自己内部节点,就可以实现 ref 的透传了!
      • useImperativeHandle,常与 forwardRef 搭配使用,可以控制向父组件暴露的属性以及方法,第一个参数即为 forwardRef 包裹后得到的父组件 ref 实例
    • useMemo与useCallback
  • Hooks思想, 比如Vue3的新API, 社区React生态也在纷纷拥抱Hooks思想, 比如上面提到的的React-ReduxuseSelectoruseDispatch, React-Use还有Umi-Hooks等等
  • Node的Cluster模块, 主从模式, 底层的Libuv
  • CI/CD
  • 埋点, 主要是以GA为代表的一键式埋点方案, 以MixAlpha/神策数据为代表的可视化埋点等
  • 测试, Jest/Enzyme/Puppeteer编写单元/集成/E2E测试
  • Flutter

五面

五面的面试官可能比较忙, 因此整个面试过程大概就二十分钟左右. 以自己的经历为主, 如果你是独行侠, 也可以讲一讲自己在社区的贡献等等, 不要直接说你喜欢独来独往一个人全干。

HR面

这一面就是常见的问题啦:

  • 大学成绩
  • 兴趣爱好
  • 有没有女朋友 俩人以后的职业规划
  • 个人职业规划
  • 成就感
  • 团队协作经历
  • 从小到大比较顺利还是坎坷(?)
  • 为什么学习前端
  • 手上有别的offer吗
  • 为什么想来阿里, 当然是因为阿里是前端的宝地了

这些问题比较主观, 为了避免误导我就不讲啦

总结&未来前端展望

对未来前端的展望是二面问到的问题, 我个人的想法主要分这么三点:

  • 多端方案, 随着5G的发展, 物联网设备也在逐渐成熟, 到时候前端程序员要适配的屏幕可能又多了几种? 我觉得未来可能会出现真正的多端解决方案, 即更全面的Rax或者Taro, 真正的一次编写处处运行. 当然理想是好的, 在它还未乘着七彩祥云到来前, 还是专心学好每一端吧~
  • 侵入后端, Serverless无疑是前端仔的下一个风口, 它给予了我们向后端进发的能力, 让我们"自己和自己联调", 也无需操心自己写的服务被流量打爆掉. 后端同学则能够解放出来, 去做一些更有意义的事情.(真的不是抢饭吃)
  • 智能化, 虽然现在到处都是赋能这个概念, 但是我还是觉得, 前端的终极之一就是赋能其他岗位, 让运营能够自己搭自己想要的活动页, 让产品爸爸自己选要对哪些控件/事件/指标进行埋点, 让不想从零学前端的后端直接拖拖拽拽配一个界面出来, 还有就是前端同学, 直接设计图生成UI代码(梦还是要有的). 虽然现在业界已经有一些方案, 但都还存在着或多或少的问题. 这也是我最感兴趣的方向之一。

    96道web前端面试题

    讲完面试经历面试题是不能少的,自己及小伙伴面试问到的题目整理出了96道题目,篇幅原因列举部分题目:

  • 什么是函数柯里化?
  • 创建对象有几种方法?
  • 怎样通过ES5及ES6声明一个类?
  • call、apply的共同点与区别?
  • 用javascript实现对象的继承,继承的几种方式,这几种方式的优缺点?
  • 说说你对作用域链的理解?
  • 谈一谈this在各种情况的指向问题?
  • 闭包的特征有哪些?
  • 闭包应用场景有哪些?
  • 实际开发中闭包的应用?
  • 如何理解js的单线程?
  • js为什么是单线程的?
  • 同步和异步的区别是什么?分别举一个同步和异步的例子?
  • 什么是任务队列?
  • 栈和队列的区别?


完整版的96道web前端面试题直接点击这免费领取噢,为我们的梦加油!

最后想说淘系面试官都很 NICE ,个人的面试风格就是比较偏闲聊那种,所以面试的时候感觉就很匹配。面试官问的问题都是具有关联性的,可能它会取你上个问题回答中的答案进行追问,给了你很大的发挥空间,让你能够充分利用你的知识体系进行回答,对于你一些不会的问题,也不会过多的追问,引导着你,同时又体现出他对你的尊重。


Tiger老师
79 声望8 粉丝