记录一次字节前端面试(2025.2.13)

12,491 阅读6分钟

前言

本人2年半左右的工作经验,第一份工作是出差比较多(低代码定制化项目,政府、军工、工业等)+ 低代码,第二份是教育行业 Saas 后台和h5相关,干了半年多被裁员了。

只做过 PC 和 h5,没有跨端经验,小程序接触过一点,但也相当于是小程序里面写点业务逻辑。

https的理解

因为不知道从哪方面说,我就说了 https 和 http 的区别
然后说到了安全性和加密,然后面试官就问我加密相关的了

HTTP和HTTPS协议的主要区别如下:

  • HTTPS协议需要CA证书,费用较高;而HTTP协议不需要;
  • HTTP协议是超文本传输协议,信息是明文传输的,HTTPS则是具有安全性的SSL加密传输协议;
  • 使用不同的连接方式,端口也不同,HTTP协议端口是80,HTTPS协议端口是443;
  • HTTP协议连接很简单,是无状态的;HTTPS协议是有SSL和HTTP协议构建的可进行加密传输、身份认证的网络协议,比HTTP更加安全。

https加密后会不会被攻击?有了解过吗?

回答:没了解过

现在了解了

首先就是非对称加密它会被中间人攻击,图示如下:

image.png

你说到了数字证书,可以详细说说吗

回答:没有深入了解过(这个时候是最开始的几个问题,都没回答上或者没回答好,已经心灰意冷了OTZ)

关于 HTTPS 的部分就看这篇文章吧:看图学HTTPS

可以说说浏览器渲染相关的吗?

回答:
1.请求后,通过HTML文件得到DOM树
2.css得到规则树
3.DOM树+CSS树得到渲染树
4.重排重绘到页面上

你提到了渲染树,你能不能详细说说渲染树?

语无伦次的说了些自己认为的(没深入了解过,GG)

详情看这篇文章,浏览器相关知识很详细:浏览器从输入URL到页面渲染加载的过程(浏览器知识体系整理)

手写一个防抖

太紧张了,第一次面大厂,脑子一片空白,居然没写出来,想死了

function debounce(fn,delay){
    let timer = null;
    return function(...args){
        if (timer) clearoutTimer(timer)
        timer = setTimeout(() => fn(...args), delay);
}

简单实现一个 EventMitter

稍微没那么紧张,只写了个大概思路,而且写的还有问题....这里复盘一下,想死

class EventEmitter {
    constructor() {
        this.event = {
            //key: arr 的形式
        }
    }

    add(name, callback) {
        // 没订阅过
        if (!this.event[name]) {
            this.event[name] = []
        }
        // 把回调加到对应函数
        this.event[name].push(callback)
    }


    delete(name, callback) {
        // 判断有没有订阅过之前
        if (!this.event[name]) {
            this.event[name] = []
        }
        // 过滤掉 name 函数中不是 callback 的回调
        this.event[name] = this.event[name].filter(eve => eve !== callback);
    }

    play(name) {
        // 拿到 name 函数中所有的回调
        const callbacks = this.event[name]
        // 调用所有回调
        callbacks.forEach(eve => {
            eve?.()
        });
    }
}

React Diff 怎么做的?

# React原理:通俗易懂的 diff 算法

说的时候说到一半面试官就打断了,说大概知道我想说什么。 然后又提到了 fiber,就继续问了 fiber

说说你对Fiber的理解

# React原理:通俗易懂的 Fiber

React做了哪些性能优化

回答:usecallback usememo memo 这些
然后问了什么时候会做以及为什么要这样做
这个就根据平时项目 + 自己的理解说了下,面试官也没继续深入了

# memo、useMemo、useCallback 你真的用明白了吗

项目里面React用了哪些hooks?

就把常用的说了

然后问了下 useEffect

useEffect 是什么时候执行的

这个我印象中有,类似于vue里面生命周期的 挂载阶段执行的,然后又继续问了

useLayoutEffect用过没?

实际项目确实没用过,然后问了下跟 useEffect 的区别

我记得 layoutEffect 是DOM挂载前,useEffect 是挂载后,然后就没问了

visibilty: hidden 和 display: none 的区别

可能是前面答的都不怎么好,所以问了个基础的

回答:前者隐藏后占据文档,后者不会;

项目里面 visibilty: hidden 和 display: none 哪个用的多?

回答:display 用的多

然后面试官问为什么,我也没想过为什么,然后从性能优化方面补了一句

回答:前者不会引起重排,只重绘

然后就没多问了

有一个场景,发送多次请求,怎么保证参数与请求对应

给的场景题,一个输入框,不小心发了两次请求,怎么保证请求和对应的参数一致

实际项目里面我没遇到过,所以当时也不知道解决办法
然后说了下避免这种情况发生,会用防抖节流这种优化

然后现在能想到的思路是:取消之前的请求或者在请求发出前保存当前请求的参数,在请求完成时比较参数,如果参数不一致则忽略响应

不知道有没有大佬来解惑一下

import React, { useState, useRef, useEffect } from 'react';
import axios from 'axios';

const CancelToken = axios.CancelToken;
let cancel;

const SearchComponent = () => {
  const [searchTerm, setSearchTerm] = useState('');
  const [loading, setLoading] = useState(false);
  const [results, setResults] = useState([]);
  const searchRef = useRef(null);

  const handleSearch = async (event) => {
    event.preventDefault();
    
    // 保存当前输入框的值
    const currentSearchTerm = searchTerm;

    // 如果存在 cancel,就取消发送
    if (cancel) {
      cancel('Request canceled due to new search');
    }

    // 如果没有 cancel,通过 axios 的 cancelToken 整一个
    cancel = new CancelToken((c) => {
      cancel = c;
    });

    setLoading(true);

    try {
      const response = await axios.get('/api/search', {
        params: { q: searchTerm },
        cancelToken: cancel,
      });

      // 比较当前这个请求和输入框的值是不是一样的,是我才响应
      if (currentSearchTerm === searchTerm) {
        setResults(response.data);
      }
    } catch (error) {
      if (axios.isCancel(error)) {
        console.log('Request canceled:', error.message);
      } else {
        console.error('Error fetching search results:', error);
      }
    } finally {
      setLoading(false);
    }
  };

  const handleChange = (event) => {
    setSearchTerm(event.target.value);
  };

  return (
    <div>
      <form onSubmit={handleSearch}>
        <input
          type="text"
          value={searchTerm}
          onChange={handleChange}
          ref={searchRef}
          placeholder="Search..."
        />
        <button type="submit" disabled={loading}>
          {loading ? 'Searching...' : 'Search'}
        </button>
      </form>
      {loading && <p>Loading...</p>}
      {results.length > 0 && (
        <ul>
          {results.map((result, index) => (
            <li key={index}>{result}</li>
          ))}
        </ul>
      )}
    </div>
  );
};

export default SearchComponent;

说下闭包吧

闭包的话看这篇# JS高频面试题合集(自用,持续更新...)

理论说完了之后然后问了下实际项目里面有没有用过闭包

说真的一时半会儿想不起来,所以就说的没有

EventLoop

# 前端进阶:看完就清楚的 JS EvenetLoop(事件循环)

微任务 宏任务你知道哪些

比如:

  • Promise.then():微任务
  • setTimeOut:宏任务
  • async、await:微任务
  • setInterval:宏任务

只说了这几个常见的微任务

你怎么定义微任务和宏任务的

这个确实没想过,就说的是学习过程中去记

然后面试官说发一个请求算哪种?

我说微任务,比如 async await 返回的 promise 嘛,promise.then 里面处理数据就是微任务,然后就没问了

后记

还根据简历上问了一些工作经历的问题

我的简历写了做了重构组件、历史遗留问题处理,就问了下怎么做重构的

还问了怎么保证重构的质量、性能(这个确实没考虑过,因为代码都太屎了,几千行的代码,优化的时候都是尽量拆分,然后把注释写清楚,保证业务先上线再说)

整个面试过程差不多一个小时吧,能回答上的也就只是能回答上,再深入一点就不知道了,不知道的是真一点不知道

只能说大厂有作为大厂的理由,诶,愿掘友们都能面上大厂