创见博客
字节前端二面(3.2 17:00)
七崽爱吃小饼干2026/03/03阅读 0专栏 前端面经
codeType
1. 讲了一下埋点库,出发点与考量。能不能有办法让埋点逻辑彻底从ui层面抽离。
2. 手动实现一下悬浮埋点和曝光埋点hooks的实现。
3. 手动实现失败重试函数的代码
4. git rebase
5. ai辅助开发实践
6. 反问公司现在最前沿的ai辅助开发实践

1. 有没有办法让埋点逻辑彻底从ui代码中抽离

主要提出了两种方式

  1. 用全埋点的方式
  2. 单独做一层业务层,把参数配置(事件的名字,参数,触发类型)的步骤统一到一个地方。然后封装一个通用的hooks,可以根据配置的参数去触发不同的hooks。然后在组件直接触发就行。这样在组件层面就不需要关心具体的用哪种hooks、参数如何配置。埋点业务参数集中也好管理。

2. 实现悬浮埋点和曝光埋点hooks

以下是悬浮埋点实现的方式,具体的获取配置和进行上报都提前封装好了。面试时写的跟这个差不多,面试后考虑了一下发现有闭包问题,所以用ref解决了一下。

tsx
import {getTrackGlobalConfig} from "../config";
import {useCallback, useEffect, useRef} from "react";
import { sendTrack } from "../core/sendTrack";

const useTrackHover = (params, config) => {
    const mergeConfig = {...getTrackGlobalConfig(), config};
    const targetRef = useRef(null);

    const latestParamsRef = useRef(params);
    const latestConfigRef = useRef(mergeConfig);

    latestParamsRef.current = params
    latestConfigRef.current = mergeConfig

    const handleFuc = useCallback(() => {
            sendTrack(latestParamsRef.current, latestConfigRef.current)
    }, [])
    useEffect(() => {
        if(!targetRef.current) return
        const ele = targetRef.current
        ele.addEventListener("mouseenter", handleFuc);
        return () => {
            ele.removeEventListener("mouseenter", handleFuc)
        }
    }, []);
    return targetRef
}

下面是我埋点库中的代码实现,曝光埋点主要就是通过IntersectionObserver这个类实现的。

ts
import {TrackConfig, TrackType} from "../../types";
import {getTrackGlobalConfig} from "../config";
import {useTrack} from "./useTrack";
import {useEffect, useRef} from "react";

/**
 * 曝光埋点 Hook - 封装元素曝光埋点逻辑,返回需要监听的 DOM 引用
 * @template T 目标元素类型(默认:HTMLElement)
 * @param eventName 曝光事件名称(必填)
 * @param customParams 自定义埋点参数(可选)
 * @param config 埋点配置项(可选,支持曝光阈值、是否只上报一次等)
 * @returns 需绑定到目标元素的 Ref 对象
 */
export const useTrackExposure = <T extends HTMLElement = HTMLElement>(
    eventName: string,
    customParams: Record<string, any> = {},
    config: TrackConfig = {}
) => {
    const mergedConfig = { ...getTrackGlobalConfig(), ...config };
    const { triggerTrack } = useTrack(
        { eventName, type: TrackType.EXPOSURE, ...customParams },
        mergedConfig
    );

    const latestConfigRef = useRef(mergedConfig)

    const targetRef = useRef<T>(null);
    const hasReported = useRef(false);

    useEffect(() => {
        if (!latestConfigRef.current.enable) return;

        const observer = new IntersectionObserver(
            (entries) => {
                entries.forEach((entry) => {
                    if (entry.isIntersecting && !hasReported.current) {
                        const exposureParams = {
                            intersectionRatio: entry.intersectionRatio,
                            boundingClientRect: entry.boundingClientRect,
                            exposureTime: Date.now()
                        };
                        triggerTrack(exposureParams);

                        if (latestConfigRef.current.exposureOnce) {
                            hasReported.current = true;
                            observer.unobserve(entry.target);
                        }
                    }
                });
            },
            { threshold: latestConfigRef.current.exposureThreshold }
        );

        const target = targetRef.current;
        if (target) observer.observe(target);

        return () => {
            if (target) observer.unobserve(target);
            observer.disconnect();
        };
    }, [triggerTrack]);

    return targetRef;
};

3. 失败重试函数的实现

我主要是通过递归的方式实现的

失败重试函数的实现

4.git rebase

git rebase

评论
0/100