字节跳动-抖音架构
一面
总时长 62min
- 自我介绍
- 为什么前把项目的状态管理方案迁移到 React Hooks
我讲了 Render props 嵌套的问题,Context 导致组件不必要重渲染的问题,为什么没用 redux ,redux 的负担。最后讲了 React Hooks 的好处
- React 有那些组件间通信的方式?
我讲了这些
父传子 props,
父传子 callback 后子组件通过 callback 更改父组件状态
Context
redux,顺便提了 react-redux 的 connect 原理
组件间共享同一个 hook
- Context 导致的子组件不必要重渲染问题怎么解决?
原因是 Context 子组件内容每次都是 React.createElement 创建的对象,引用是会变的,即使内容完全没改变。
解决方案:将子组件通过 children props 传进来,保证引用不变,变更的只是 props.children 这个对象的属性。
- 了解 React Fiber 吗?
我讲了 Stack Reconcile 时代的问题(递归不可中断更新,性能问题,没有任务优先级)。Fiber 基于链表做可中断的更新,并且讲了 React 放弃 requestIdleCallback 而选择自己编写 scheduler 的原因。
- 进程和线程的区别?
讲了各自的定义和区别之后,我还详细说了 Chrome 为什么采用多进程架构(安全沙箱隔离,页面关闭后释放地址空间,减少内存碎片,崩溃问题)。
- 进程间通信有哪些方法?
匿名管道,有名管道,信号量,消息队列,socket
- JS 异步解决方案?
我讲了 callback 以及它的问题(callback hell 以及错误处理麻烦),Promise 的好处(链式调用,错误统一.catch() 处理),然后提到 async / await ,讲了协程机制,async / await 底层的 generator 实现,隐式的 Promise。
- 事件循环?
常规题,讲宏任务微任务 UI 渲染,不多赘述。
- 跨域有哪些方案?
我提了 jsonp , cors,并且详细说了简单请求和复杂请求,预检请求,还有 iframe domain.name ,nginx 反向代理
- 手写 jsonp
这里没写好,我 jsonp 实际上没有真正使用过。自己实践都是用 cors 做的。。。
- 水平垂直居中怎么实现?
讲了 flex,absolute + translate,inline-box + vertical-align: center + text-align: center, 顺便扯到了 table 布局的性能问题。
JS 的数据类型
document.querySelectorAll('div') 返回的是一个什么类型?如何遍历它?
它是一个对象,是一个类数组。通过 迭代器遍历,数字索引遍历,for of 语法糖,顺便提了 for of 语法糖的实现。
1***委托?常规题
event.currentTarget 与 event.target 分别是什么?
这个的输出?
js
var a = 10;
(function (){
console.log(a);
a = 5;
console.log(window.a);
var a = 20;
console.log(a);
})()
答:undefined, 10, 20
- 算法题,特征数据转成一个树。
太紧张了😨,只写出来最简单的情况。不过说了下思路。
二面
总时长 54 min
- 自我介绍
- 什么时候开始接触前端的?
- 先聊点基础吧,说一下 OSI 网络模型,并且每层的协议?
OSI 应该是七层的那个,我当时说的是 TCP/IP 四层模型,说了这些
应用层:http, dns, ftp, smtp, pop3;
传输层:TCP UDP ;
网络层:IP, RIP, OSPF
数据链路层:ARP
不过面完查了下,RIP 和 OSPF 应该是应用层协议。
- 聊聊 TCP 和 UDP 的区别?
TCP 面向连接,UDP 尽最大努力交付,无连接
TCP 首部 20 字节,UDP 首部 4 字节
TCP 是可靠传输,详细讲了 TCP 保证可靠传输的机制
还详细说了 TCP 慢启动,滑动窗口,重传机制
- 我们正在使用的面试视频是采用什么协议实现的?
答:UDP,因为要降低延迟,UDP 快首部开销小,并且视频通话容忍少量数据的丢失。
- https 的 s 是什么?
s 是 ssl,然后详细讲了 ssl 握手的过程。并且详细说了浏览器认证数字证书合法性的过程(证书链向上查找合法 RootCA 记录),还提到了 CRL (证书吊销列表)的更新不及时可能导致的问题 ,由此扯到了 OSCP 在线证书检查协议询问 RootCA。
- 302 和 304 的区别?
302 暂时重定向,并且讲了 302 网站劫持,影响搜索引擎排名的问题。304 Not Modified,协商缓存内容没有改变。同时聊了下缓存机制,强缓存未过期直接返回 200 并且不会向服务端发出请求。
- 手写代码,基于链表实现 push 与 shift。
- 聊项目?为什么技术选型选择了 Umi + Dva?
讲了项目具体的历史包袱,然后讲了 Umi 的设计思想及它解决的问题,并且刚好符合那个项目的具体场景,内容很长不赘述(。
至于 Dva 部分,我首先讲了 React 原生的状态管理机制的问题,Context 导致子组件不必要重渲染的开销,然后切入到 redux 将 redux 的思想(因为 Dva 是基于 redux 的一种优化解决方案)。最后引申到 Dva 的设计思想,解决了 Redux 的哪些痛点。中间我还扯了 redux-saga 的实现以及 dva 是如何集成 saga 的,还扯了协程的问题。这里内容也很长很细不赘述。建议大家针对这种关键性的问题好好准备并且了解整个链路的思想与原理,便于在面试的过程中表现自己的竞争力。想了解 react 相关的设计思想的同学可以去知乎搜「张立理」老师的文章,他的文章给了我很多启发与收获。
- 你在这个项目中推广了基于 GitFlow 的 CI / CD 上线流程,能详细说说整个过程吗?
从 develop 分支 checkout 到 feature 分支进行开发,所有 commit 到远程库的代码都会跑质量流水线(lint 与 test cases),然后 feature 开发完之后 merge develop 前有 MR 检查,MR 检查除了跑质量流水线外还要生成一个线上的测试地址,以便检查。MR develop 后,等到要发板时,merge master ,同样 merge master 之后 跑质量流水线和发布测试地址,最后打 tag 发版,跑部署流水线构建发布到 OSS。
不清楚的同学可以去看看 Git Flow ,还有流水线的设计相关的书籍。推荐《 持续交付2.0 业务引领的DevOps精要》,乔梁老师讲得很好。
线上的代码放哪?答:OSS + CDN
如何保证发布后 CDN 代码是最新的?
首先讲了下 CDN 的原理,然后给每个文件打包输出时加上 [contentHash], 文件内容变化时文件名必定变化。顺便扯了下 [hash] 和 [contentHash] 的区别。然后 index.html 不要设置缓存,因为打包后 index.html 内引用的 scirpt url 发生了变化(因为 contentHash),因此可以知道最新的 js 文件。并且 CDN 配置了监听 OSS 的更新事件,触发回源更新。
- 有没有为这个项目做什么优化?
首先从网络讲起,讲了 http 1.1 升级到 http 2 的优化。(使用同一个 TCP 连接,HOLB 问题优化,Server Push,HPACK)
还提到了动画页面对动画的性能优化,rAf 还有单独建立图层保证 reflow 不影响其它元素,以及 GPU 加速。
- 有对 SPA 做什么特别的优化吗?
讲了基于路由的 code splitting / lazy loading,还有基于某些需要打开 modal 才会使用但又很少使用的模块做了 dynamic import
然后提到了构建时的 Tree shaking,首先讲了 Tree Shaking 的原理:harmony import / export 标记,然后交给 terser 进行提出,还提了下 sideEffect。然后讲 webpack tree shaking 的配置。还有将了下如何编写易于 Tree shaking 的代码(要将每个工具函数单独 export ,不要集成为一个 class ,tree shaking 的最小单元是一个对象,它不能识别一个对象中哪些函数是否需要
- 你项目使用 TS 写的,那你知道 TS 如何编译到 ES 5 代码的吗?
思考了十秒钟,一开始是懵的。突然想通,这不就是问 babel 原理么。然后就将 TS 的词法分析,聊了下 DFA 。然后就是基于文法做语法分析,构建语法树。后面把 AST 交给 Babel。Babel 遍历 AST,在遍历的过程中根据每一个 AST Node 的类型,交给 Babel 对应的 Plugin,在这个切入点引申到 Babel 的插件机制。讲了下插件的 visitor 的作用。最后转换程 ES 5 的 AST,同时在这个过程中能得到 SourceMap。然后将 ES 5 的AST 还原成代码,即得 ES 5 代码。
- 如果 TS 代码编译的过程中,遇到了一些高级的特性,ES 5 并不支持怎么办?
引入对应特性的 polyfill
三面
- 自我介绍
- 为什么从上一段实习离职?
- 大二去实习怎么平衡学业和工作的关系?
- 项目中提到的数据图表渲染优化是怎么做的?
根据数据特征实现 sampling 算法取样,只需要取关键点,重复的无变化的数据剔除,减少渲染数据量。
- 简历中有提到你在学校团队中推广落地了 Code Review ,你具体是怎么做的?
先找团队中技术好有影响里的几位同学,单独做一个小项目,先在这个小项目内应用 Code Review。先让这些同学熟悉 Code Review 的流程,以及 Code Review 能给他们带来什么,让他们认识到 Code Review 的价值,能够带来好处之后,再在大项目中,联合这些同学一起推广 Code Review
- 如何评价 Code Review 质量 ?
抽检 CR ,看评论内容是否有意义。看 Request For Changes 之后的代码修改是否有经过设计思考。CR 是一个相互学习的过程,如果看到双方对某个设计问题有所争论,那也便是好事。
- 你认为什么样的代码是好代码
讲了一些 OOP 封装复用的思想,SOLID 设计原则。也提了实际业务场景与代码提前设计的矛盾。
- 聊简历中的命令行工具设计?// 经历强相关,不便分享~
- 怎么评价这个工具推广的效果?
- 使用命令行工具将需求单状态实现自动化更新的话?会不会带来一些不好的影响?
- 手写代码,写 timeFormat 函数。包含占位符解析
如:timeFormat(new Date().getTime(), ‘YYYY-MM-DD hh:mm’); // 2021-02-26 14:02
思路:一遍扫描。用词法分析的思想,YYYY MM DD 这些就是关键词。识别到关键词替换成对应的值。
- 写上面这题过程中,遇到了 string 类型的不可变性问题。顺便谈下可变与不可变
- 手写代码:实现一个随输随搜的搜索框
首先讲需要注意哪些点:1. 触发搜索防抖 2.响应内容保证按需返回 3. 服务端限定处理的关键词长度 ,只去前面 n 个。因为太长的关键字会使得 Elastic Search 效率低下
- 除了这些方面呢?用户体验方面上你会怎么设计?
常搜索的关键词做缓存,以后输入如果匹配上了历史搜索,历史搜索关键词的排序会更靠前。
搜索框的 outline 交互。还有搜索框的 a11y 优化,以方便特殊人士使用
默认 focus,减少用户一次点击
对违法词汇搜索的结果信息过滤
根据用户特征与地理位置返回特定的结果(因为我经常使用 Google,Google 就是这么做的
- 还有吗?从前端输入到服务端性能整个链路角度来看,有什么可以优化的点吗?如何降低用户操作的折损?
这个问题问出来的时候,脑子里就认为这是一个商业化实验数据相关的问题。
- 我们在京东上搜某些商品,为什么会在抖音上推送相关的内容呢?这是怎么实现的?
讲了广告联盟的思想,数据买卖与共享
- 跨域怎么收集用户数据?
- 跨域不能共享 Cookie 但是可以知道用户的唯一标识符,通过用户唯一标识与同时接入的第三方平台实现数据共享。
- 怎么最终用户?有哪些常用的标识?
IMEI,MEID,ICCID,手机号
- 手写代码:节流,防抖 前面问了太多意料之外的东西,导致我很紧张。防抖节流怎么写都想不起来了😭
- 入职时间,实习多久?
面试过程体验很好,面试官善于引导,并且问题都很有深度