字节跳动前端面试

一面

约的 10 月 17 日下午三点,14:42 进直播间,此时室友都还在睡觉。面试官大概三点过了几分才进来。简单的介绍了一下(没听清他说自己姓啥了)糊了一下就开始面试了。尽量还原一下情景,顺序可能有偏差。

1. 介绍一下自己

幸好看了一下 moy 的面经,拿出了提前准备好的稿子开始吟唱

2. 介绍一下你做过的项目罢

虽然没有提前准备过,但好歹都是自己亲生的娃,拿机房监控的项目吹了一下。中间问了几个技术问题,比如用了什么框架之类的。

当然,提到用 Websocket 传输视频的时候面试官两眼发光,给后面的问题打下了坚实的伏笔

3. 你遇到最难的问题以及怎么解决的

一群背时研究生学长,跑的识别的代码不晓得在哪的 tutorial 改的,rtmp 识别完就变成 rawvideo 了。我在网上找了一堆方案最后拼出来了一个免去可以用的(flv.js + node-fluent-ffmpeg + 给学长的代码插了一段 socket 传 rawvideo 到 node 的 py)

4. 刚刚听你提到了 Websocket,能讲讲有什么特点吗

TCP,双向连接,持久不断开,兼容有问题

伏笔很快的就冒了出来,要不是用了好几次 Websocket 还写过一个同构的 json-websocket 工具怕是要遭

4.1 你用什么东西查的兼容性呢

有个网站

4.1.1 你平常在什么地方翻文档呢

MDN,刚刚那个网站是 canIuse

十分尴尬的忘了丢出来 StackOverflow 和 Google

4.2 Websocket 用的是什么库

ws

难不成我还会说用的是 express-ws 是因为别人给的 demo 是用的这个库

4.3 Websocket 整个过程都是 socket 吗

当然不是,前面要走 HTTP 来升级

4.3.1 那 Upgrade 时候返回的 HTTP 状态码是多少

101 Switching Protocol

还好之前写浏览器同构 WS 的时候看了一眼

4.4 了解视频流吗

仅限项目用到的

除了找怎么直播的时候看过一点各种直播方案以外还真没看过,可以看出来面试官是经常用 Websocket 而且还对视频直播很熟悉的,说不定是抖音那边的前端

5.1 js 怎么判断把类数组转换成数组

[...arr], Array.from(arr)

5.1.1 有 ES5 的方法吗

写个 for 循环一个一个 push

直到写文的时候才想起来 ES5 通篇的都是 Array.prototype

5.1.2 那怎么判断数组

Array.isArray(), arr instanceof Array

“类数组判断不了吧”“判断不了吗”

当然判断不了啊,类数组都是一些名字都叫不出来的特殊类

5.2 讲一下 js 为什么要用异步

大概讲了下同步会阻塞 UI 影响用户体验

5.3 了解事件循环吗

宏任务和微任务那个吗(都讲一下吧) 开始口胡一通,这种东西看一下文档就会了,你问我他是啥我还真讲不出来

之前写 funcode 的时候就魔改过引擎的背时事件循环(加了一个用时间戳的事件系统),也被 Unity 背时的多重循环(Unity 应该是跑了好几个线程的循环)搞过,但是没怎么看过浏览器和 libuv 的东西。(突然想起自己还是看过一点背时的 epoll)。只能拿着宏任务和微任务吹一吹

5.6 这有一道题,讲一讲它的输出

console.log('script start') //1
async function async1() {
  await async2()
  console.log('async1 end') //5
}
 
async function async2() {
  console.log('async2 end') //2
}
 
async1()
 
setTimeout(function () {
  console.log('setTimeout') //8
}, 0)
 
new Promise((resolve) => {
  console.log('Promise') //3
  resolve()
})
  .then(function () {
    console.log('promise1') //6
  })
  .then(function () {
    console.log('promise2') //7
  })
console.log('script end') //4
console.log('script start') //1
async function async1() {
  await async2()
  console.log('async1 end') //5
}
 
async function async2() {
  console.log('async2 end') //2
}
 
async1()
 
setTimeout(function () {
  console.log('setTimeout') //8
}, 0)
 
new Promise((resolve) => {
  console.log('Promise') //3
  resolve()
})
  .then(function () {
    console.log('promise1') //6
  })
  .then(function () {
    console.log('promise2') //7
  })
console.log('script end') //4

在纸上画队列的时候面试官怀疑我在切 tab 搜答案,安逸牛客网,lose focus 了都不得通知

5.6.1 我在 setTimeout 后面加个 requestAnimationFrame 应该怎么输出

不清楚不知道没用过

6 你的简历上面写了对 Vue 挺熟悉的,那问你几个 Vue 的问题

6.1 你用了多久 Vue

大二做二手市场的时候用的,之后就一直在用

6.2 Vue 的双向绑定是怎么实现的

用的 Object.defineProperty(不过没说变异数组方法和后面改成 Proxy 了)

6.2.1 具体呢?出了一个例子

define 了 setter,然后变动的时候触发了 setter 更新 vDOM,再和 DOM 比较渲染

6.2.2 是和 DOM 比较吗

不知道,也有可能是和上一个时刻的 vDOM 吧

不知道,不清楚,没看过

6.3 vue.nextTick() 用过吗

不知道,不清楚,没用过

7. 又发过来一道题

var x = 3
var y = 4
var obj = {
  x: 1,
  y: 6,
  getX: function () {
    var x = 5
    return (function () {
      return this.x
    })()
  },
  getY: function () {
    var y = 7
    return this.y
  },
}
console.log(obj.getX()) //5
console.log(obj.getY()) //6
var x = 3
var y = 4
var obj = {
  x: 1,
  y: 6,
  getX: function () {
    var x = 5
    return (function () {
      return this.x
    })()
  },
  getY: function () {
    var y = 7
    return this.y
  },
}
console.log(obj.getX()) //5
console.log(obj.getY()) //6

“5 和 7 吧”

“是吗”

“不对感觉是 5 和 6”

“5 和 6 对吧”

“应该是吧”

“那 this 指向的是哪呢”

”getX 的作用域吧”

“作用域吗,好吧”

后来在 console 里面跑了一下发现是 3 和 6,return 的函数 this 指向的是 window。

背时函数,安逸箭头函数。

8. 平时做算法题吗

不做

8.1 那我选道简单点的

给定一个数组代表某支股票连续多个交易日的价格。你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。

Input: [2, 3, 5, 1, 4]

Output: 3

Input: [ 5, 3, 2, 1]

Output: 0

一眼就看出来肯定是解法肯定是 O(n) 的,然后陷进 DP 列状态转移出不来了

非常无奈的写了暴力,面试官非常努力的鼓励我也想不出来

9. 居中应该怎么写

我用的多的 flex 和绝对定位,但是也可以 table-cell 和 margin

面试官:“margin 啊...”

9.1 用绝对定位写一个居中

position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);

10. 你有什么问题想问的吗

“这个团队有多少人呢”

“不清楚,我不是他们团队的”

一面总结

感觉表现的并不咋样,有好多东西都没有想起来。算法一如既往的垃圾,我太菜了罢。面试大概 50 分钟,结束后一个小时 HR 电话通知一面过了,约了二面。

二面

二面的面试官好像在家里,但是又会时不时左右望一下,让人十分迷惑。但是周日加班也太惨了。跟一面一样面试官晚了几分钟才进房间。

1.做个自我介绍吧

掏出简介开始吟唱

2.讲讲做过的项目吧

跟一面几乎一样的梦幻开头,拿出二手市场开始吹

3.有什么技术难点吗

二手市场讲了讲记录查看位置,压缩图片之类的,然后又抱着智慧课堂那个直播讲了一遍

3.1 你们这项目组多少人

我 + 俩 java 后端 + python

3.2 这个 node 也是你写的吗

是的

3.3 这个 Websocket 有鉴权吗

没有的(实际上 socket 的 url 都是后端返回拼出来的)

3.3.1 那要实现鉴权该怎么办

“配上 java 后端吗”“是的” 那就 java 登陆后返回 token,前端带着 token 去请求 websocket 面试官想了一会,非常不情愿的说好像可以 看起来他有一个别的方案,但是带 token 不是单点登陆的正常操作么

4.有没有做过前端安全方面的

(实际上没做过)硬着头皮糊了个 XSS

4.1 XSS 是什么原理

一瞬间仿佛看见了 moy 面后端写的面经,脱口而糊 实际上拿了之前在 CTF 看 XSS 看到的一段背了出来 背时,没写过 XSS,现在 CTF 都不咋流行了

4.2 还有其他的吗

想起刚看的面经里面有一个跨域(虽然算不上啥安全问题),赶紧糊了上去试图转移话题

4.2.1 跨域有哪些头

只记得两个,实际上有三四个

4.2.2 怎么处理跨域问题

后端加跨域头

4.2.3 还有吗

JSONP,但是没用过 还有我们用的 Websocket 也不会受跨域限制,因为鉴权是手动实现的,Websocket 后端可以随时断开连接

5.给一道题

if (!Function.prototype.bind){
    Function.prototype.bind = function (o) {
        if (typeof this !== 'function') {
            throw TypeError("Bind must be called on a function");
        } else {
            //Write here
            let args = [...arguments].slice(1)
            return () => this.apply(o, [...args, ...arguments])
        }
}
if (!Function.prototype.bind){
    Function.prototype.bind = function (o) {
        if (typeof this !== 'function') {
            throw TypeError("Bind must be called on a function");
        } else {
            //Write here
            let args = [...arguments].slice(1)
            return () => this.apply(o, [...args, ...arguments])
        }
}

一开始写的时候写的return () => this.apply(this, [...args, ...arguments])被面试官提醒参数 o 没有用到才改回来 (而且还忘了绑 prototype, 但面试官似乎没有发现) 面试官似乎短暂的理解不能,解释了一下 this 指向的是调用 bind 的函数之后反应过来 “嗯,应该也可以” 那是当然,毕竟我提前写了一下,在浏览器稍微调试过

6.又给了一道题

这算法简直完全不用脑子,跟上一轮的一比就是 Easy 嘛

function findMaxDuplicateChar(str) {
  let maxChar = '',
    maxValue = 1
  //Write here
  let dict = {}
  for (let i = 0; i < str.length; i++) {
    if (str[i] !== ' ') dict[str[i]] = dict[str[i]] ? dict[str[i]] + 1 : 1
  }
  for (let c in dict) {
    if (maxValue < dict[c]) {
      maxValue = dict[c]
      maxChar = c
    }
  }
  return {
    maxChar,
    maxValue,
  }
}
const str = 'this is a fe test at toutiao on September'
console.log(findMaxDuplicateChar(str)) // output: { maxChar:"t", maxValue:7 }
function findMaxDuplicateChar(str) {
  let maxChar = '',
    maxValue = 1
  //Write here
  let dict = {}
  for (let i = 0; i < str.length; i++) {
    if (str[i] !== ' ') dict[str[i]] = dict[str[i]] ? dict[str[i]] + 1 : 1
  }
  for (let c in dict) {
    if (maxValue < dict[c]) {
      maxValue = dict[c]
      maxChar = c
    }
  }
  return {
    maxChar,
    maxValue,
  }
}
const str = 'this is a fe test at toutiao on September'
console.log(findMaxDuplicateChar(str)) // output: { maxChar:"t", maxValue:7 }

第一次遍历出来是空格(8 次),确认了一下不算空格以后写了一下 ''.join(str.split(' '))发现跑不起来 背时 JS,连 join 都没有 然后在循环里面加了个 if 判断 “这个跑的起来吗” 我在 QQ 里面回了一下消息发现面试官毫无反应 点了一下提交运行结果是对的 “跑的起来” “那行吧” 面试官似乎不是非常擅长算法,倒是 moy 那个面试官相反

7.还有什么要问的吗

问了一下是啥部门的(广州的效率工程) 干什么的(to B) “我们会在一周之内通知你结果”

二面总结

在听到一周之内通知的时候都感觉要凉了,毕竟前面答的很糊,而且上次一面之后一个小时就收到了电话。周一上午在厕所里的时候接到面试过了的电话,约了周四电话面。

Loading New Comments...