抖音前端二面面经

概括

过去一年跳槽了两次,最近的一年都在面试,失败了很多次,也拿了很多offer,腾讯,字节,虾皮,滴滴都oc,最终人生的第三方份工作选择了腾讯,工作空闲之余,把最近一年的面经整理一下。

联系我wx:Chan-FE 可腾讯内推~

抖音二面面经

  1. 介绍项目亮点,负责的模块
  2. webpack升级过程做了哪些优化,提升了多少,具体的指标
  3. 三种哈希的使用区别是什么,为什么css使用contenthash
  4. webpack升级优化过程中踩了什么坑,或者说两个版本差异需要注意的地方
  5. 除了这些还有别的优化手段嘛,用到的没用到的都可以说一下
  6. webpack热更的原理
  7. websocket的原理
  8. TLS握手的过程
  9. 对前端安全方面的理解
  10. 简单请求和复杂请求
  11. 代码输出题
  12. 最接近的两数和
  13. 模拟网络请求,最多重试5次,初始等待为1s,每次时间乘以2

项目

1.介绍项目亮点,负责的模块

前端技术框架升级,webpack4升级webpack5

2.webpack升级过程做了哪些优化,提升了多少,具体的指标

  1. 压缩算法优化,主要说一下Terser和uglify这些常见算法的区别与压缩效果对比
  2. tree-skaing优化,tree-skaing引用副作用导致打包压缩得不够极致(副作用解释:例如在utils文件夹下面有index.js文件,用于系统导出utils里面其他文件,好处就是写的少, 不管 utils 里面有多少方法,我都只需要引入 utils 即可。这个时候,如果有一个函数A在外界没有用到,但是他在 utils/index.js 里面被引用了,使用了而 tree-shaking是不能它摇掉的,这个 A 就是副作用),这个时候通过配置sideEffects可将副作用摇掉。
  3. 长缓存机制,通过splitchunk抽离公共代码,固定moduleid和chunkid
  4. 打包命名优化,js使用chunkhash, css使用contenthash
  5. js相关的产物由7点多兆下降到5点多兆

3.三种哈希的使用区别是什么,为什么css使用contenthash

  1. 全局hash由全部的文件公共决定生成。
  2. chunkhash 根据不同的入口文件进行依赖文件解析、构建对应的 chunk,生成对应的哈希值。只要我们不改动同一个chunk的某一个文件的代码,就可以保证其哈希值不会受影响。
  3. contenthash只跟文件自身有关系。
  4. css文件hash使用contenthash,这样不受js模块变化影响,只要css不变化,都不用重新生成css 产物
  5. js使用chunkhash是因为js作为入口文件,对Css存在引用关系,当css发生变化的时候,css产物的命名也会变化,这个时候js要感知同一个chunk的css命名的变化,进行引入调整,所以只能使用chunkhash

4.webpack升级优化过程中踩了什么坑,或者说两个版本差异需要注意的地方

  1. 移除tree-shaking副作用的时候,会把css的引入也当初副作用给打掉,sideEffects要忽略样式文件
  2. webpack5内置了压缩器terser-webpack-plugin,可以免配置开箱即用,但是如果同时配置了其他压缩器,会导致terser的失效,这个时候也需要对terser进行相关的配置
  3. 内置了缓存模块,不再需要引入持久缓存的第三方插件/loader
  4. file-loader等变成了内置的assets-modules

5.除了这些还有别的优化手段嘛,用到的没用到的都可以说一下

  1. hybird长会话机制,在页面启动阶段就可以取容器上次的缓存数据先展示,后面再根据登录态做动态更新
  2. 切分chunk的时候不能切得太小也不能切得太大,要充分利用http的并行优势
  3. 首页主动推送功能,请求html的时候就把相关css js给推送过来
  4. ssr服务端渲染

八股

6.webpack热更的原理

  • 启动webpack,生成compiler实例。compiler上有很多方法,比如可以启动 webpack 所有编译工作,以及监听本地文件的变化。
  • 使用express框架启动本地server,让浏览器可以请求本地的静态资源
  • 本地server启动之后,再去启动websocket服务,通过websocket,可以建立本地服务和浏览器的双向通信。这样可以实现当本地文件发生变化,立马告知浏览器可以热更新代码

7.websocket的原理

全双工、二进制帧、握手(需要握手才能正式收发数据)

握手的过程为,客户端发送的请求中包含了 Upgrade: websocketConnection: Upgrade 以及一个 base 编码的密文,用于简单的认证密钥。服务器返回 Upgrade: websocketConnection: Upgrade 表示接受 webSocket 协议的客户端连接,返回一个密钥用于验证客户端请求报文,防止误连接。

8.TLS握手的过程

内容较多,可查看知乎文章分享:https://zhuanlan.zhihu.com/p/662069195

9.对前端安全方面的理解

xss、csrf、csp、指纹追踪、css安全键盘时间、爬虫与反爬以及业务做的反扒处理

10.简单请求和复杂请求

简单请求不会触发预检

请求方法是以下三种方法之一:
HEAD
GET
POST

HTTP的头信息不超出以下几种字段:
Accept:指定返回类型,: text/plain(纯文本类型), text/html(html类型)
Accept-Language 指定返回语言
Content-Language 指定内容语言
Last-Event-ID
Content-Type:只限于三个值
application/x-www-form-urlencoded:对发送内容进行编码
multipart/form-data:上传的表单内包含文件
text/plain:发送内容为纯文本格式

复杂请求会先发option预检查

算法

11.代码输出题

const p1 = new Promise((resolve, reject) => {
  console.log('1');
  resolve();
  console.log('2');
})

p1.then(() => {
  console.log('3');
  Promise.resolve(() => {
    console.log('4');
  }).then((res) => {
    console.log('5', res);
  });
  console.log('6');
})

console.log('7');

// 1 2 7 3 6 5

12.最接近的两数和

function testNear (arrNear: Array<number>, targetNear: number): number {
    // 排序
    arrNear.sort((a, b) => a - b);
    let left = 0, right = arrNear.length - 1;
    let res: number = 0;
    while(left < right) {
        // 这里的结束边界不能是left <= right
        // 因为arrNear[left]和arrNear[right]需要是不同的元素
        // 《首尾收缩遍历》
        const temp = arrNear[left] + arrNear[right];
        if(temp === targetNear) {
            return res;
        } else if (temp > targetNear) {
            // 尾部收缩
            right--;
        } else {
            // 头部收缩
            left++;
        }
        // 更新最接近的值
        res = Math.abs(targetNear - res) > Math.abs(targetNear - temp) ? temp : res;
    }

    return res;
}

// const arrNear = [24,69,14,37];
// const targetNear = 60;
// const nearP = testNear(arrNear, targetNear);
// console.log({ nearP }); // { nearP: 61 }

13.模拟网络请求,最多重试5次,初始等待为1s,每次时间乘以2

const timer = (time) => {
  console.log({ time });
  return new Promise((resolve) => {
    setTimeout(resolve, time);
  })
}

const test = async () => {
  let index = 0;
  let flag = false;
  let time = 100;
  while(index < 5 && !flag) {
    await new Promise((resolve, reject) => {
      const successFlag = Math.random() > 0.5;
      if (successFlag) {
        resolve(successFlag);
      } else {
        reject(successFlag);
      }
    }).then((successFlag) => {
      flag = true;
      console.log('请求成功', index, successFlag);
    }).catch((successFlag) => {
      console.log('请求失败', index, successFlag);
      index++;
    })

    // 成功就不需要等待了
    if (!flag) {
      await timer(time);
      time *= 2;
    }
  }
}

test()
// 请求失败 0 false
// { time: 100 }
// 请求成功 1 true

搞了个公主号《 FE前端指南 》,感兴趣的可以关注一下~

全部评论
卧槽 好牛 请问是已经有工作经验了吗 还是刚毕业进字节啊
点赞 回复 分享
发布于 03-18 18:02 广东

相关推荐

评论
3
50
分享

创作者周榜

更多
牛客网
牛客企业服务