字节飞书前端面试

3,998 阅读8分钟

更多面试内容,可查看我的面试记录专栏

以下答案为面试后整理,并非面试中的回答。

一面

状态:通过

1. 自我介绍

你好,我是XX,我现在在XX主要负责XX小程序,主要做负责相关的功能的迭代,以及线上小程序线上性能的提升。
从去年X月开始负责的小程序,从负责到现在,小程序的FMP从xxms降至800ms左右,到达率从xx%提升至xx,白屏从0.22降至0.18。
在X月之前,主要负责XX相关业务,负责的内容有 XXX、XXX、XXX。其中比较重要的项目有XX机制的升级,影响XXX业务。以及 xx业务的 xxxx项目,有上亿的流量,最后 XX 收益约占总收益的三分之一

2. 根据自我介绍了问了 小程序性能优化的细节

性能检查清单 性能优化主要有6个方面:

1.优化小程序包

  • 优化逻辑层层js代码体积,如合理的封装组件,删除无用代码,合理划分组件等
  • 提升最低基础库版本以接入多种包优化方式。例如小程序在3.270.0才支持的生命周期onPrefetch

2.提前核心请求发送时机

  • 检查所有核心页面的request是从那个生命周期发出的,如果发出核心request的生命周期,执行时间小雨250ms。例如:xx小程序通过性能时序图可知,在将核心请求提前至onPrefetch生命周期后,核心请求发出大约在88ms左右。
  • 减少异步端能力/Promise的使用以尽快发出请求。保存端能力返回的结果,例如:用户的定位信息,用户系统的信息
  • 避免发出多次核心request。页面fmp仅出发一次核心request
  • 延后首屏渲染非必要request。例如:在xxx详情页中,就有两个接口,一个接口是获取 主体信息,一个接口是获取评论数据,我们是可以将获取评论这个接口,等首屏渲染完成后再发出。

3. 优化核心请求服务器响应时长

  • 优化核心请求服务器响应时长。这个是需要根据现有请求耗时,评估出需要优化的接口(根据现有耗时、流量、成本),推动后端同学进行优化
  • 配置prelink以加速网络请求
  • 服务端开始gzip

4. 优化首屏渲染

  • 按需渲染,检查核心setData渲染的非可视区域显示内容/显示屏幕时图体积的比例来判断状态
  • 避免在fmp前频繁调用setData。如果setData次数少于3则为通过
  • 避免长时间处理请求数据。核心请求结束到核心setData的调用时间间隔,小于15ms,为通过

5. 避免不必要的swan API/console调用

  • 避免重复swan API调用,评判标准重复调用swan API的同步累积耗时小雨10ms,则通过,大于20ms,为优先,大于50ms为高优。重复调用用swan API的判断标准是:500ms内,调用相同的API,函数参数与返回参数完全一致。
  • 避免console。线上尽可能不要使用console 前端性能优化篇之console.log

6. 优化图片使用

  • fmp前,不在可视区域的图片均开始lazy-load属性
  • 避免请求过大的图片。页面中所有图片的宽高乘积小于实际显示宽高乘积 * (设备像素比 ^ 2)
  • 防止页面抖动,fmp前,页面中的图片宽高适中保持不变

3. 小程序的架构是什么样子的,有了解过微信小程序或者其他小程序吗?

小程序框架性能优化实践

先简单介绍一下小程序的开发流程

  • 首先我们用swan写布局
  • 接着通过开发者工具打包,上传到我们的小程序到B端服务器,(如果是内部,我还是通过流水线进行上线发布的)
  • 最后小程序的审核流程,有机审、人审
  • 最后是用户点击小程序时,客服端请求小程序C段服务器,C端服务器再从B端服务器获取小程序包,整个过程都是加密传输,可以保证代码的安全。

SWAN
智能小程序的框架,命名为SWAN。自上而下分层结构如下:

  • 第一层是开发者基础库,命名为swan-js,开发者直接和这层打交道。swan-js负责两件事:(1) swan代码转换为HTML,变成webView可运行机制(2) 客户端端能力的封装暴露
  • 第二层层是swan-native。这里面最核心的是API和组件NA实现。其中双栈管理也在这一层,另外Extension用于开发者宿主自身能力扩展使用。
  • 第三层这层为Porting-layer。这层是小程序为了实现开源,增加的一层与宿主的接口层。
  • 最下层是宿主的基础能力层。如果宿主没有这些能力。可以参考我们公司开源的示例,可直接集成到宿主使用

4. 算法题

function countAndSay(n) {
    let arr = ['1', '11'];
    if(n <= arr.length) {
        return arr[n - 1];
    }
    let i = 1;
    while(!arr[n - 1]) {
        let pre = arr[i];
        let item = '';
        let count = 1;
        let cur = pre[0];
        for(let j = 1; j <= pre.length; j++) {
            let next = pre[j];
            if(cur !== next) {
                item += count + cur;
                cur = next;
                count = 1;
            }
            else {
                count++;
            }
        }
        i++;
        arr.push(item);
    }
    return arr[n - 1];
}

5. VUE数据双向绑定的原理

Vue 内部通过 Object.defineProperty方法属性拦截的方式,把 data 对象里每个数据的读写转化成 getter/setter,当数据变化时通知视图更新

更多详细解答:0 到 1 掌握:Vue 核心之数据双向绑定

6. FLEX的基础知识,flex-shrink,flex-grow,flex-basis

flex-shrink:当空间不足以展示的时候,是否被压缩
flex-grow:当内容超过既定的空间,是否放大
flex-basis:压缩和方法的基准,没设置的时候为width的值
Flex 弹性布局

7. 如何实现一个FLEX相同功能

暂时没找到答案,后续完善

8. 为什么离职,对下一份工作的期望,问了我觉得什么样工作是我觉得有挑战的

离职原因:

  1. 现在的工作过于重复,希望进一步的提升自己
  2. 我喜欢更有挑战的工作

什么是有挑战的工作?
更想做一些基础的插件的封装

有了解过可视化方面吗?
有,自己忙完这段时间,也有这方面学习的计划

二面(20220321)

面试官是一个非常nice的小姐姐
状态:未通过

项目

写一个once修饰器

vue源码解析事件派发(onon、emit、onceonce、off)

vue中key的作用

Vue中 key 值的作用
vue中key的作用和工作原理
为什么 Vue 中不要用 index 作为 key?(diff 算法详解

vue中如何隐藏一个元素

v-show: 会渲染dom,display:none
v-if:惰性渲染,条件为false时,不会渲染dom,成本更高

CSS怎么隐藏一个元素,对回流和重绘的隐藏,对事件响应机制的影响

更详细分析,可以查看五种方法隐藏元素,成本消耗以及对事件的影响

方式回流重绘事件响应的影响
visible: hidden无法点击
opacity: 0可以点击
display: none无法点击,可以模拟点击
z-index利用层叠上下问隐藏dom无法点击
position 定位在可视范围之外无法点击

如何隐藏父元素,子元素显示

  • 父 visibility hidden 子visibility visible
  • 父定位(position)定位到可视范围之外,子元素再定位回可视范围

如何垂直居中一个元素

  • postion + margin
  • postion + transform
  • flex
  • 单行文本元素line-height

输入url到页面渲染

  • 浏览器进程的UI线程捕获到用户输入的url,并调用网络线程
  • 网络线程进行域名解析(DNS),获取到ip地址,并判断是否为安全网址(safebrowsing)
  • 若是安全网址,继续建立连接(TCP),拿到服务端返回的数据,并发数据传给UI线程
  • UI线程,调用渲染器进程,通过IPC通过把数据传递给渲染器进程
  • 渲染线程 DOM、CSSOM、Layout tree、layer tree和绘制样式表、栅格化、合成器帧
  • 合成器帧传给浏览器进程,浏览器使用GPU绘制

Event Loop

setTimeout(() => {
    console.log(1);
}, 0);
new Promise((resolve) => {
    console.log(2);
    resolve(3)
}).then(res => {
    console.log(res);
});
async function foo() {
    console.log(4);
};
(async () => {
    await foo();
    console.log(5);
})();

答案:2 4 3 5 1

算法,获取连续子数组最大和

function sum(arr) {
    if(arr.length === 0) {
        return {
            max: 0,
            resArr: [];
        }
    }
    let max = arr[0];
    let resAee = [arr[0]];
    let start = 0, end = 1;
    let temp = max;
    for(let i = 1; i < arr.length; i++) {
        if(temp + arr[i] > 0) {
            temp += arr[i];
        }
        else {
            temp = arr[i];
            start = i + 1;
            end++;
        }
        
        if(max < temp) {
            max = temp;
            resArr = arr.slice(start, end);
        }
    }
    return { max, resArr };
}

写在最后

祝大家面试顺利,拿到满意的offer,更多面试题关注我的面试记录专题。有什么疑问欢迎评论