星火无限
面试定位
这份题目基于星火无限 JD 和简历内容整理,重点覆盖 SDK 平台、Next.js + React 架构、App Router、Turborepo Monorepo、iframe 通信、数据上报与调度、前端性能、安全、监控调试、实时通信、跨端兼容、故障排查和团队技术指导。回答都按可直接口述的方式组织。
速记提纲
30 秒定位
9 年 Web 开发经验,最近担任 Web 开发负责人,主导 Swee AI 社交娱乐平台和 RYZZ Web3 直播社交平台的 Web 架构、核心开发和团队管理。技术主线是 TypeScript、React、Next.js、Node.js、NestJS,做过 Prompt SDK、埋点 SDK、WebSocket + Protobuf 实时通信、PWA、SSR 重构、Turborepo Monorepo 和复杂 Canvas/SVG 编辑器。
和星火无限 JD 的匹配点
- SDK 平台:Prompt 模板 SDK、事件埋点 SDK、WebSocket 通信层、钱包交互封装、文件上传与配置中心,都有 API 设计、版本兼容、调试和接入体验经验。
- Next.js 架构:Swee、RYZZ 使用 Next.js,虎牙做过 React SSR 重构,能讲 SSR/SSG、Hydration、App Router、缓存、SEO 和首屏优化。
- 数据上报与监控:事件埋点系统包含 SDK 缓冲、sendBeacon/fetch/XHR 降级、Kafka 削峰、PostgreSQL JSONB + GIN、Grafana 看板。
- 工程化:Turborepo、pnpm workspace、内部包沉淀、CI/CD、Docker/Kubernetes、灰度发布和代码生成都有实践。
- 复杂通信与跨端:RYZZ 做过 WebSocket + Protobuf,H5/WebView、PWA、移动端兼容、iframe/postMessage 机制可以结合跨端和 WebView 经验展开。
必讲项目
- Swee Prompt 模板管理系统:100+ Prompt 模板、版本控制、Playground、SDK、多级缓存、4 批灰度迁移。
- Swee 事件埋点分析系统:前端 SDK、数据上报、Kafka、PostgreSQL、Grafana、代码自动生成。
- Swee AI 移动端 PWA:Next.js、SSE 流式响应、IndexedDB、Service Worker、性能优化。
- RYZZ Web3 主站:Next.js SSR、WebSocket + Protobuf、实时通信封装、钱包 SDK 风格 API。
- 虎牙 SSR 重构:React SSR、服务端数据预取、Hydration、缓存和灰度,秒开率提升 41%。
- 凡科快图编辑器:Vue + Canvas/SVG、图层、变换矩阵、Web Worker + OffscreenCanvas,复杂交互与性能优化。
高频面试题
Q1: 请做一个和星火无限岗位匹配的自我介绍
答案:
我叫李文杰,有 9 年 Web 开发经验,最近担任 Web 开发负责人,负责 Swee AI 社交娱乐平台和 RYZZ Web3 直播社交平台的 Web 架构、核心开发和团队管理。我的主线是 TypeScript、React、Next.js、Node.js/NestJS,同时做过 Vue + Canvas/SVG 编辑器、SSR 重构、PWA、实时通信和中台系统。
和这个岗位最匹配的是 SDK 平台和工程化经验。我做过 Prompt 模板 SDK、事件埋点 SDK、WebSocket + Protobuf 通信封装、Web3 钱包交互封装,也做过 Turborepo Monorepo、数据上报、性能优化、监控调试和技术文档。这个岗位强调 SDK API、Next.js 架构、数据上报和开发者体验,这些正好是我近几年项目里反复落地的方向。
Q2: 你为什么觉得自己适合这个岗位?
答案:
我理解这个岗位不是单纯做页面,而是做 SDK 平台、Web 应用架构和工程化基础设施。我的经历里有直接对应的部分:埋点系统里做过从 SDK、上报、Kafka 到看板的完整链路;Prompt 模板系统里做过 SDK、多级缓存、灰度和版本管理;RYZZ 做过 WebSocket + Protobuf 的实时通信封装;虎牙做过 React SSR 重构和性能优化。
所以我能从 API 设计、接入体验、稳定性、监控调试、文档和团队推广几个维度理解 SDK 类产品,而不是只把它当成一个 npm 包。
Q3: 这个岗位的核心能力你怎么理解?
答案:
我认为有四类核心能力。第一是 SDK API 设计,接口要稳定、易用、可扩展、可兼容;第二是 Next.js + React 架构能力,能处理 SSR、App Router、缓存、SEO 和性能;第三是工程化能力,包括 Monorepo、内部包、CI、构建优化和版本治理;第四是线上稳定性,包括数据上报、监控、调试、安全和故障排查。
这些能力组合起来,目标是让业务接入更快、线上更稳、开发者体验更好。
Q4: 你做过哪些 SDK 类项目?
答案:
主要有四类。第一是事件埋点 SDK,负责事件缓冲、批量上报、sendBeacon/fetch/XHR 降级、页面生命周期兜底。第二是 Prompt 模板 SDK,业务通过模板 key 和变量获取渲染结果,内部处理缓存、版本、灰度和降级。第三是 RYZZ 的 WebSocket + Protobuf 通信层,上层只订阅事件,不关心连接、重连、心跳和消息缓冲。第四是 Web3 钱包交互封装,统一处理连接、签名、allowance、approve、gas 估算和链上确认。
这些都不是简单工具函数,而是面向多个业务方的稳定能力。
Q5: 设计一个 SDK API 时你最关注什么?
答案:
我会关注五点:易用性、稳定性、可扩展性、可观测性和兼容性。易用性是初始化简单、默认配置合理、错误信息清楚;稳定性是异常不影响宿主业务;可扩展性是通过插件、hooks 或配置扩展,不频繁改主 API;可观测性是内置 debug、日志、上报和版本信息;兼容性是升级不破坏已有接入。
SDK 的 API 一旦发出去就很难改,所以宁愿前期多做设计和试用,也不要上线后频繁 breaking change。
Q6: SDK 初始化 API 你会怎么设计?
答案:
我会设计成一个明确的 init 方法,接收 appId、env、user、debug、transport、plugins 等配置,并返回一个 client 实例。全局单例适合埋点 SDK 这类全站能力,但我也会支持显式实例化,方便多应用、多环境或测试场景。
配置上要有合理默认值,比如默认批量上报、默认超时、默认降级策略。必填项缺失时要在开发环境直接报清楚,生产环境则降级失败并记录错误,不能让 SDK 把宿主页面拖崩。
Q7: SDK 版本管理和向后兼容怎么做?
答案:
我会遵循 SemVer。patch 修 bug,minor 增加兼容能力,major 才做 breaking change。SDK 和服务端协议要有版本协商,比如请求头带 sdkVersion、protocolVersion,服务端按版本兼容解析。
对于废弃 API,我不会马上删除,而是先标记 deprecated,在开发环境提示迁移方案,保留一到两个大版本窗口。大版本升级要配迁移文档、codemod、changelog 和灰度发布,服务端还要统计各版本调用量,确认旧版本占比降下来再下线。
Q8: SDK 如何设计插件机制?
答案:
插件机制适合把核心能力和扩展能力拆开。核心只负责初始化、生命周期、事件总线、配置和上报;插件通过 hooks 注入,比如 beforeSend、afterSend、onError、onReady。埋点 SDK 可以用插件扩展 PV、页面停留、性能采集;Prompt SDK 可以用插件扩展缓存、日志、降级。
插件要有明确顺序和错误隔离,一个插件异常不能影响核心流程。还要暴露类型定义,让业务方写插件时能获得完整 TypeScript 约束。
Q9: SDK 如何保证不会影响宿主页面性能?
答案:
首先包体要小,核心包和可选插件拆开,支持 tree shaking。其次初始化不能阻塞首屏,非关键能力延迟启动。第三,上报、缓存、计算都要异步化,批量合并请求,避免频繁操作 DOM 或同步 localStorage。第四,异常要被 SDK 内部捕获,不能让业务页面崩。
埋点 SDK 里我用 10 条或 5 秒双触发缓冲,就是为了减少请求数和主线程压力。
Q10: SDK 的错误处理你会怎么设计?
答案:
SDK 错误要分级。配置错误属于开发期错误,开发环境应该明确抛出或 console warn;网络错误属于运行时错误,要重试或降级;业务错误要返回结构化 error code;不可恢复错误要进入内部错误上报。
对宿主业务来说,SDK 最重要的是“不添乱”。即使上报失败、缓存失败、插件失败,也不应该影响页面主流程。
Q11: SDK 的 debug 模式怎么做?
答案:
debug 模式要能看到初始化配置、当前版本、队列长度、上报 payload、请求结果、重试次数和错误原因。开发环境可以 console 输出,生产环境可以通过 query 参数或 localStorage 开关临时打开。
对于平台型 SDK,我还会做一个调试面板,显示最近事件、协议版本、连接状态、缓存状态和服务端响应。这样接入方遇到问题时,不用只靠猜和问 SDK 作者。
Q12: SDK 文档和接入指南怎么写才好用?
答案:
我会按开发者真实接入路径写。第一部分是 5 分钟快速接入,给最小可运行代码;第二部分是完整配置说明;第三部分是常见场景;第四部分是错误码和排查;第五部分是迁移指南和版本兼容说明。
文档必须包含真实示例、TypeScript 类型、常见错误和调试方法。SDK 文档不是说明书,而是开发者体验的一部分。
Q13: SDK 为什么一定要有 TypeScript 类型?
答案:
类型就是 SDK 的契约。通过类型可以约束配置项、事件名、事件属性、返回值和错误码,减少接入方猜字段。比如埋点 SDK 根据事件定义生成类型后,事件名拼错、属性漏传都能在编译期发现。
TypeScript 类型还会影响 IDE 自动补全和文档体验,对内部 SDK 来说,这是提升接入效率最直接的方式。
Q14: SDK 如何做多端兼容?
答案:
我会先定义运行环境能力矩阵,比如浏览器、移动 WebView、SSR、Node.js、小程序是否支持 window、document、localStorage、sendBeacon、IndexedDB。SDK 初始化时先做 feature detection,再选择不同 adapter。
例如上报能力可以有 BeaconTransport、FetchTransport、XHRTransport;存储可以有 IndexedDBStorage、LocalStorageStorage、MemoryStorage。这样核心逻辑不依赖具体环境,多端兼容就会更清晰。
Q15: iframe 通信机制你会怎么设计?
答案:
我会基于 postMessage 设计稳定的消息协议。消息必须包含 type、id、version、source、payload、timestamp,请求响应类消息还要有 correlation id。父页面和 iframe 先握手,确认 origin、协议版本和能力列表,再允许业务消息通信。
协议要版本化,不能直接传随意对象。所有消息都要校验来源和 schema,避免安全问题和兼容问题。
Q16: postMessage 如何保证安全?
答案:
第一,发送时 targetOrigin 不能用通配符,必须是白名单 origin。第二,接收时校验 event.origin 和 event.source,只接受可信窗口。第三,校验消息结构和版本,不认识的 type 直接丢弃。第四,敏感操作要做权限和二次确认。
iframe 通信很容易因为“能通就行”而忽略安全,实际上它相当于跨应用 API,必须按协议和权限治理。
Q17: iframe 父子页面如何做握手?
答案:
我会让 iframe 加载后先发送 ready,父页面收到后返回 init,包含会话 id、配置、权限、协议版本和允许的能力。双方确认版本兼容后进入 connected 状态。
如果一段时间没握手成功,父页面要展示错误状态或重试。握手成功前,不处理业务消息,避免 iframe 未准备好导致消息丢失。
Q18: postMessage 请求响应如何避免串包?
答案:
每个请求生成唯一 id,响应里带 requestId。父子两端维护 pending map,收到响应后按 requestId resolve 对应 Promise。请求要有超时,超时后从 pending map 删除并返回明确错误。
对于广播类消息,比如 resize、route-change,可以不走 request-response,但也要有 type 和 version,避免不同消息混用。
Q19: iframe 高度自适应怎么做?
答案:
iframe 内部用 ResizeObserver 监听内容高度变化,通过 postMessage 把 height 发给父页面,父页面设置 iframe 高度。为了避免频繁抖动,要做节流和最小变化阈值。
如果内容里有图片或异步加载,需要在资源加载后再次通知。移动端还要考虑软键盘、横竖屏和安全区域。
Q20: iframe sandbox 你会怎么配置?
答案:
sandbox 默认会限制脚本、表单、弹窗、同源访问等能力。我会按最小权限开放,比如需要脚本就加 allow-scripts,需要表单就加 allow-forms,需要同源能力才加 allow-same-origin。不要一次性全开。
如果 iframe 运行第三方内容,sandbox 很关键。它能降低 XSS、跳转、弹窗和权限滥用风险。
Q21: 跨域问题你怎么处理?
答案:
浏览器跨域本质是同源策略限制。接口跨域常用 CORS,服务端配置允许的 origin、methods、headers 和 credentials。前端如果带 cookie,要 credentials: 'include',服务端不能用通配符 origin。
iframe 和父页面跨域时不能直接访问 DOM,要通过 postMessage。调试跨域时我会看预检请求、响应头、cookie SameSite、域名和协议是否一致。
Q22: WebView 跨端调试你有什么经验?
答案:
我做过 H5 和移动端 WebView 场景,常见问题包括缓存不更新、JSBridge 不可用、软键盘遮挡、滚动穿透、iOS 日期解析、文件上传兼容、支付/登录回跳。调试上 iOS 用 Safari Web Inspector,Android 用 Chrome inspect,必要时加远程日志和 SDK debug 面板。
跨端产品不能只在桌面 Chrome 验证,必须覆盖主流机型、系统版本和 WebView 容器。
Q23: Next.js App Router 和 Pages Router 区别是什么?
答案:
Pages Router 通过页面文件和 getServerSideProps、getStaticProps 做数据获取;App Router 默认使用 Server Components,通过 page.tsx、layout.tsx、loading.tsx、error.tsx 等约定文件组织路由。
App Router 的重点是嵌套路由、共享 layout、Streaming、Server Components 和更复杂的缓存模型。新项目我会优先 App Router,但老项目迁移要按页面渐进,不能一口气重写。
Q24: App Router 的缓存模型你怎么理解?
答案:
App Router 里有请求级 memoization、Data Cache、Full Route Cache 和客户端 Router Cache。fetch 可以通过 cache、next.revalidate、tag 控制缓存,mutation 后可以用 revalidateTag 或 revalidatePath 主动刷新。
我会把稳定配置、内容页、公共数据缓存起来,把用户强相关或实时数据设成动态。缓存用错会出现数据不更新,所以必须为每类数据定义清楚缓存策略。
Q25: SSR、SSG、CSR 怎么选?
答案:
内容稳定、SEO 重要的页面适合 SSG;首屏体验和 SEO 都重要但数据动态的页面适合 SSR;强交互后台或登录后页面可以 CSR;局部内容可以客户端补充。
选择时看数据实时性、访问量、缓存能力、服务端成本和 SEO 诉求。虎牙 M 站更适合 SSR,中后台表格页很多时候 CSR 就够。
Q26: Server Components 适合放什么?
答案:
Server Components 适合数据获取、静态结构、权限过滤和不需要浏览器状态的 UI。它能减少客户端 bundle,也能把敏感逻辑留在服务端。
但涉及 useState、useEffect、浏览器 API、事件交互的部分必须是 Client Component。边界划分原则是:能在服务端完成的就放服务端,必须交互的才下发客户端。
Q27: Hydration 不一致怎么排查?
答案:
常见原因是服务端和客户端初始数据不同,或者首屏渲染依赖了时间、随机数、window、localStorage、用户环境。排查时我会先看报错组件,再确认服务端 HTML 和客户端首屏状态是否一致。
解决方式是统一初始数据,浏览器相关逻辑放到 effect 里,动态区域必要时改成客户端渲染。
Q28: Next.js SEO 怎么做?
答案:
基础是 title、description、canonical、Open Graph、结构化数据、sitemap、robots 和语义化 HTML。App Router 里可以用 Metadata API 静态或动态生成 meta。
技术上还要保证首屏内容服务端可见,避免关键内容只在客户端异步渲染。性能也是 SEO 的一部分,LCP、CLS、INP 都会影响真实效果。
Q29: Streaming SSR 解决什么问题?
答案:
Streaming SSR 可以先返回页面壳和快数据,再把慢数据分段流式注入。这样慢接口不会阻塞整个 HTML 返回,用户更早看到首屏。
我会用 Suspense 切分边界,比如首屏主体先渲染,推荐列表、评论、次要模块异步流式加载。边界不要切太碎,否则调试和性能都会变复杂。
Q30: App Router 里错误边界怎么设计?
答案:
全局要有 root error,业务子路由可以放自己的 error.tsx 和 not-found.tsx。错误页要能重试、能上报、能展示 requestId,方便排查。
对于关键模块,我会用局部 Error Boundary,避免一个推荐模块失败导致整个页面白屏。
Q31: 你怎么做首屏性能优化?
答案:
我会先量化指标,看 LCP、FCP、TTFB、INP 和资源瀑布。优化上包括 SSR/SSG、代码分割、图片压缩与懒加载、CDN、缓存、减少首屏接口、请求聚合和减少主线程长任务。
虎牙 SSR 重构里,我们通过服务端数据预取、请求聚合、缓存和灰度优化,让页面秒开率平均提升 41%。
Q32: Lighthouse 分数低你怎么排查?
答案:
我会先看是哪一项低:Performance、Accessibility、Best Practices、SEO。性能再细分 LCP、CLS、INP、TBT。LCP 低看最大内容资源、服务器响应和图片;CLS 看图片尺寸、字体、动态插入;INP/TBT 看长任务和事件处理。
排查后要结合真实用户监控,Lighthouse 是实验室数据,不能完全代表线上用户。
Q33: Performance Profiler 你怎么用?
答案:
我会录制用户卡顿场景,看主线程火焰图,判断是 JS 执行、样式计算、布局、绘制还是图片解码。React 项目还会配合 React DevTools Profiler 看组件重渲染。
定位后再决定方案,比如拆分计算、Web Worker、虚拟列表、memo、批量更新、懒加载或减少 DOM 节点。
Q34: React 重复渲染怎么优化?
答案:
先定位重复渲染来源:父组件状态变化、props 引用变化、context 更新、key 不稳定。优化顺序是先拆状态边界,再用 React.memo、useMemo、useCallback 稳定引用。
在 AI 对话里,历史消息不应该因为新 token 一直重渲染,所以我会把消息组件 memo 化,并用 requestAnimationFrame 合并 token 更新。
Q35: 长列表怎么优化?
答案:
长列表优先虚拟滚动,只渲染可视区域和缓冲区。列表项高度要稳定,key 要可靠,图片要懒加载并预留尺寸。
聊天列表还要处理向上加载历史、滚动位置保持、新消息定位和未读提示,比普通列表更复杂。
Q36: 动效和交互体验怎么兼顾性能?
答案:
动效优先用 transform 和 opacity,避免频繁触发布局。复杂动画用 requestAnimationFrame 或 Web Animations API,避免在滚动和输入时做重计算。
我会尊重 prefers-reduced-motion,对低性能设备降级。动效的目标是增强反馈,不是炫技。
Q37: 前端安全你重点关注哪些?
答案:
常见是 XSS、CSRF、点击劫持、敏感信息泄露、上传风险、依赖漏洞和跨域配置错误。前端避免直接渲染不可信 HTML,必须渲染时用白名单清洗;鉴权 token 不随便暴露;iframe 要设置 CSP、sandbox 和 origin 校验。
SDK 平台还要防止接入方误用,比如泄露 appSecret、上报敏感字段、开放危险 postMessage 能力。
Q38: XSS 怎么防?
答案:
输入不可信,输出要按上下文转义。React 默认会转义文本,危险点是 dangerouslySetInnerHTML、富文本、Markdown、URL、第三方脚本。需要渲染 HTML 时用 DOMPurify 这类白名单清洗。
同时配合 CSP,限制脚本来源,减少 XSS 成功后的危害。
Q39: CSRF 怎么防?
答案:
CSRF 的关键是浏览器会自动带 cookie。防护方式包括 SameSite Cookie、CSRF Token、Referer/Origin 校验,以及对高风险操作做二次验证。
如果使用 token 放 Authorization header,天然比纯 cookie 更不容易被 CSRF,但仍要注意 XSS 和 token 泄露。
Q40: 点击劫持怎么防?
答案:
可以通过 X-Frame-Options 或 CSP 的 frame-ancestors 限制页面被哪些站点 iframe 嵌入。对于必须被嵌入的 SDK/组件页,要做来源白名单和能力限制。
如果是 iframe SDK 平台,不能简单禁止嵌入,而是要允许可信宿主,拒绝未知来源。
Q41: 数据上报 SDK 怎么设计?
答案:
我会设计事件队列、批量缓冲、失败重试、页面卸载兜底和 debug 能力。埋点 SDK 里我用 10 条或 5 秒触发批量上报,发送方式优先 sendBeacon,再降级 fetch 和 XHR。
服务端先校验再投递 Kafka,Consumer 批量入库。这样前端低侵入,服务端也能抗峰值。
Q42: 数据上报为什么要批量?
答案:
逐条上报会增加请求数、耗电、占用网络和服务端压力。批量能减少连接开销,提高吞吐。但批量太大又会增加延迟和丢失风险。
所以我通常用数量 + 时间双触发,比如前端 10 条或 5 秒,Consumer 500 条或 5 秒,在实时性和吞吐之间平衡。
Q43: sendBeacon 有什么限制?
答案:
sendBeacon 适合页面卸载或切后台时发送少量数据,不阻塞页面跳转。但它大小有限、无法自定义复杂请求、响应不可读,也有兼容性差异。
所以我不会只依赖 sendBeacon,而是设计 sendBeacon、fetch、XHR 多级降级。
Q44: 数据上报丢数据怎么排查?
答案:
我会按前端 SDK、接入层、Kafka、Consumer、数据库、看板分段排查。先确认是哪个事件、哪个时间段、丢多少,再对比各段计数:前端发送数、服务端接收数、Kafka 写入数、Consumer 入库数、看板查询数。
如果前端发送少,查 SDK 初始化、触发条件、队列、广告拦截、WebView 限制;如果 Kafka 后少,查投递、Lag、rebalance、死信队列;如果入库对但看板少,查 SQL 口径、时间窗口和缓存。
Q45: 监控与调试能力怎么建设?
答案:
我会按“目标定义 → 埋点采集 → 链路打通 → 可视化 → 告警 → 排障闭环”这几个阶段建设,而不是一上来就堆日志。
第一步,先定义要解决的问题和指标。SDK 平台最核心的是接入是否成功、上报是否成功、数据是否准、接口是否稳定。所以我会先定义指标:SDK 初始化成功率、配置拉取成功率、上报成功率、队列堆积数、重试次数、丢弃数、接口 P95/P99、错误率、不同 SDK 版本的调用量和异常率。
第二步,SDK 侧先把可观测信息采出来。SDK 内部要记录版本、appId、env、协议版本、能力检测结果、队列状态、flush 次数、最近请求、错误码、插件状态和降级原因。开发环境通过 console/debug 面板展示,生产环境按采样上报 SDK 自身诊断事件。这里要注意脱敏,不能把用户隐私和 token 写进日志。
第三步,服务端侧做分段计数和 traceId 串联。每次 SDK 上报带 traceId、sdkVersion、appId,服务端接入层记录接收数、校验失败数、投递 Kafka 成功数;Kafka 记录 topic、partition、lag;Consumer 记录消费数、入库成功数、死信数;数据库记录写入延迟和慢查询。这样一旦反馈“数据丢了”,可以从 SDK 发送、网关接收、Kafka、Consumer、DB、看板逐段对账。
第四步,建设调试工具。我会提供 SDK debug 面板和平台调试台。debug 面板给接入方看:当前版本、配置、队列、最近事件、最近请求、错误原因;平台调试台给平台团队看:某个 appId、某个用户、某个 traceId 的完整链路。最好支持导出诊断包,让接入方反馈问题时一键复制上下文。
第五步,做看板和告警。Grafana 或内部监控看板按 appId、环境、SDK 版本、事件类型展示成功率、延迟、错误率、丢弃数。告警要分级:上报接口 5xx、成功率跌破阈值、Kafka lag 激增、Consumer 入库失败属于高优先级;某个低流量事件缺字段可以低优先级通知负责人。
第六步,形成排障 Runbook 和复盘机制。比如“上报成功率下降怎么查”“某业务说丢数据怎么查”“SDK 初始化失败怎么查”,每类问题都有固定步骤和负责人。事故后补监控、补日志、补文档或补 SDK 防御逻辑。监控与调试能力的目标不是收集很多数据,而是让线上问题能快速定位、快速止血、持续变少。
Q46: 埋点事件定义平台有什么价值?
答案:
事件定义平台可以统一事件名、属性、枚举、触发时机和说明,避免各业务手写字符串导致口径混乱。基于定义还能生成 TypeScript 类型和埋点代码。
这样数据分析更可信,SDK、服务端校验和看板也能围绕同一份定义工作。
Q47: PostgreSQL JSONB + GIN 为什么适合埋点?
答案:
埋点有公共字段,也有大量差异化属性。公共字段如事件名、用户、时间做普通列和 B-tree 索引,扩展属性放 JSONB,配合 GIN 索引支持属性查询。
这样既不需要频繁改表结构,又能保留一定查询性能。但核心字段不要都塞 JSONB,否则聚合和索引会变麻烦。
Q48: WebSocket + Protobuf 的收益是什么?
答案:
WebSocket 适合双向实时通信,Protobuf 相比 JSON 更紧凑,适合高频消息。在 RYZZ 里,Protobuf 相比 JSON 节省约 50% 带宽。
我还封装了消息类型分发、心跳、自动重连、指数退避、消息缓冲和状态重放,让业务层只关心事件。
Q49: WebSocket 断线重连怎么设计?
答案:
用心跳检测连接状态,断线后指数退避重连,避免瞬间打爆服务。重连期间待发送消息进入队列,恢复后重新订阅频道并拉取状态快照。
实时系统重连后最重要的不是“连上”,而是状态重新一致。
Q50: HTTP、SSE、WebSocket 怎么选?
答案:
普通请求响应用 HTTP;服务端单向推流,比如 LLM token、进度、日志,用 SSE;需要双向实时互动,比如直播、多人协同、实时状态,用 WebSocket。
选择协议要看方向、频率、可靠性、兼容性和服务端成本。
Q51: 大流量实时场景你会关注什么?
答案:
关注连接数、消息频率、带宽、序列化成本、心跳、重连风暴、服务端扩容和消息顺序。前端还要避免高频消息导致渲染抖动,用队列、节流、合批更新。
RYZZ 的 WebSocket + Protobuf 项目让我对实时通信的状态一致性和连接治理有实际经验。
Q52: Turborepo 给项目带来什么收益?
答案:
Turborepo 适合多应用、多包协作。它能做任务编排、增量构建和缓存,只构建受影响的包,提高本地和 CI 速度。
在 Swee 这类包含 Web、后台、SDK、组件库和工具包的项目里,Monorepo 还能统一规范和复用内部包,减少多仓库同步成本。
Q53: pnpm workspace 的优势是什么?
答案:
pnpm 通过内容寻址存储和硬链接减少磁盘占用,workspace 能让多个包在同一仓库内互相依赖和联调。它对幽灵依赖控制更严格,能暴露依赖声明不规范的问题。
配合 Turborepo,可以形成内部包开发、构建、测试、发布的一体化流程。
Q54: Monorepo 里内部 npm 包怎么治理?
答案:
包要有清晰边界,比如 ui、utils、sdk、types、config。每个包要有 owner、README、版本、changelog 和测试。公共包不要随意依赖业务包,避免依赖倒置。
发布上可以用 Changesets,配合 CI 自动生成版本和 changelog。业务升级时要有迁移指南和兼容窗口。
Q55: Monorepo 依赖管理容易出什么问题?
答案:
常见问题是循环依赖、隐式依赖、版本不一致、公共包过度膨胀。解决方式是限制包依赖方向,CI 检查依赖图,统一核心依赖版本,公共包保持小而清晰。
Monorepo 不是把所有代码放一起就好,关键是边界和治理。
Q56: 构建优化你会怎么做?
答案:
先看构建耗时分布,再做增量构建、缓存、并行、减少无效编译、拆分包边界、优化 Babel/TS 配置。生产包体优化看 tree shaking、代码分割、依赖替换和按需加载。
Turborepo 解决任务级缓存,Vite/esbuild/SWC 解决编译速度,二者关注点不同。
Q57: Webpack 和 Vite 怎么取舍?
答案:
Vite 开发体验好,基于 ESM 和 esbuild 预构建,适合新项目和中后台。Webpack 生态成熟,可控性强,适合复杂历史项目和特殊构建需求。
我不会为了新而新,项目选型要看生态、迁移成本、插件需求、团队熟悉度和产物要求。
Q58: React Native 你怎么回答?
答案:
我没有把 React Native 作为最近主线,但理解它的基本架构:JS 线程、原生线程、Bridge/JSI、新架构 Fabric/TurboModules。我的跨端经验更多来自 H5、PWA、WebView、JSBridge 和移动端兼容。
如果岗位涉及 RN,我可以从 React 状态管理、组件模型、接口层、性能排查和跨端协作切入,再补齐原生模块和新架构细节。
Q59: H5 游戏接入你怎么理解?
答案:
H5 游戏接入重点是加载速度、资源缓存、横竖屏、适配、音频策略、支付登录、数据上报和容器通信。如果游戏运行在 iframe 或 WebView 中,还要设计消息协议和安全边界。
我虽然没有专门做大型 H5 游戏,但做过 H5、WebView、PWA、实时通信、埋点 SDK 和复杂 Canvas/SVG 编辑器,这些能力可以迁移到游戏接入场景。
Q60: Unity WebGL 对接要关注什么?
答案:
Unity WebGL 关注包体、加载进度、缓存、内存、浏览器兼容、全屏、音频、输入事件和 JS 通信。前端通常要提供容器、加载 UI、错误兜底、数据上报和 JS bridge。
如果和业务系统通信,可以通过 JS 方法暴露给 Unity,再由前端转发到 SDK 或后端。核心是定义稳定协议,避免 Unity 和 Web 两边互相耦合。
Q61: 你如何设计 SDK 的消息协议?
答案:
协议字段要稳定,包括 version、type、id、timestamp、payload、meta。请求响应要有 requestId,错误要有 code、message、detail、recoverable。
协议还要支持扩展,新增字段不影响旧版本,新增 type 要有默认忽略策略。所有协议都应该有文档和测试用例。
Q62: SDK 怎么做灰度发布?
答案:
先发 beta 或 next tag,让内部业务接入验证。服务端按 sdkVersion 统计错误率、调用量和性能,确认稳定后再发布 latest。对于托管脚本 SDK,还可以按 appId、业务线、比例下发不同版本。
灰度要有快速回滚能力,SDK 平台最怕一次升级影响所有接入方。
Q63: SDK 包体怎么优化?
答案:
核心包只放必需能力,可选能力拆插件;使用 ESM 支持 tree shaking;避免引入大依赖;polyfill 由宿主决定;构建产物提供 modern 和 legacy 版本。
同时用 bundle analyzer 看依赖体积,避免一个小 SDK 引入一整个工具库。
Q64: SDK 如何支持 SSR?
答案:
SDK 不能在模块顶层直接访问 window、document、localStorage。要把浏览器能力放在初始化阶段或 adapter 内,通过环境检测判断是否可用。
在 Next.js 里,客户端 SDK 应该只在 Client Component 或 effect 中初始化;服务端只用纯函数或 Node adapter,避免 SSR 报错。
Q65: SDK 如何做降级?
答案:
降级要按能力分层。例如上报失败可以缓存后重试;sendBeacon 不可用降级 fetch;IndexedDB 不可用降级 localStorage 或 memory;实时连接失败可以改轮询或提示弱网。
降级不是静默失败,debug 模式和监控里要能看到降级原因。
Q66: SDK 如何设计配置中心能力?
答案:
配置要支持环境、业务线、版本、灰度和回滚。客户端读取配置时走缓存,服务端发布新版本时通过版本号或失效事件刷新。
我做过配置中心和 Prompt 模板多级缓存,思路类似:内存短缓存、Redis 中缓存、DB 兜底,发布时主动失效。
Q67: SDK 如何做权限控制?
答案:
SDK 本身不要持有高权限密钥。前端只拿临时 token 或 appId,敏感操作由后端鉴权。比如 OSS 上传,前端先向后端申请临时签名,再直传 OSS。
iframe 或 postMessage 场景下,工具能力也要按宿主 origin、用户身份和业务线授权。
Q68: 技术选型你一般怎么做?
答案:
我会先看业务目标和约束,再比较候选方案的成熟度、生态、性能、团队熟悉度、维护成本和迁移成本。关键风险做 PoC,不靠争论拍脑袋。
方案文档里要写清为什么选、为什么不选、风险是什么、怎么验证。技术选型不是追新,而是对业务负责。
Q69: 从 0 到 1 做复杂模块你怎么推进?
答案:
先确认目标、边界、成功指标和风险,再拆模块、接口、数据模型、状态流和发布计划。高风险点先做 PoC,核心链路先闭环,非核心能力迭代补齐。
我做 Prompt 模板系统就是先跑通编辑、变量、渲染、Playground、SDK,再补审批、灰度、评估和更多治理能力。
Q70: 需求评审你关注什么?
答案:
我关注用户场景、业务目标、边界条件、异常状态、数据来源、权限、性能和上线节奏。评审时会把模糊需求转成可验收条件,避免开发到一半才发现理解不一致。
复杂需求还要提前识别跨团队依赖,比如后端接口、设计资源、运营配置、测试数据。
Q71: 技术方案评审你怎么写?
答案:
我会写背景、目标、非目标、模块设计、数据流、接口、状态、缓存、性能、安全、监控、灰度、风险和回滚。替代方案也要列出来,说明取舍。
好的方案文档不是越长越好,而是让团队快速知道怎么做、为什么这么做、风险在哪里。
Q72: 联调测试你怎么提高效率?
答案:
提前确定接口契约、mock 数据、错误码、分页和权限。前端用类型和 schema 校验接口,后端提供稳定测试环境。联调问题用 checklist 记录,避免重复踩坑。
我还会推动接口代码生成和 mock 自动化,把重复联调成本降下来。
Q73: 部署上线你关注什么?
答案:
关注构建产物、环境变量、缓存、灰度、回滚、监控和告警。上线前有 checklist,上线后看错误率、接口耗时、性能指标和业务指标。
如果是 SDK 发布,还要关注版本渗透率和接入方反馈,不能只看包发出去了。
Q74: 线上故障你怎么处理?
答案:
先止血,再定位,再修复,最后复盘。止血可能是回滚、切流、关闭开关、降级。定位看监控、日志、最近发布、影响范围和可复现路径。
复盘要补监控、补测试或补流程,不只是写一篇总结。
Q75: 白屏问题怎么排查?
答案:
先看是否资源加载失败、JS 报错、接口阻塞、SSR/Hydration 错误、路由异常或 CDN 缓存问题。通过错误监控、Performance、Network、Console 和用户环境定位。
前端要有 Error Boundary、资源失败兜底、白屏检测和快速回滚能力。
Q76: 页面卡顿怎么排查?
答案:
用 Performance 录制,看主线程长任务。常见原因是大列表渲染、频繁 setState、复杂计算、同步存储、大图片解码、布局抖动。
解决方式包括虚拟列表、memo、Web Worker、requestAnimationFrame 合批、懒加载和减少 DOM。
Q77: 接口慢导致页面慢怎么办?
答案:
先看接口是否必须首屏依赖。必须依赖的做服务端聚合、缓存、并发和超时;非首屏依赖的延后加载或骨架屏。还要看是不是前端串行请求导致瀑布。
虎牙 SSR 重构里,我们通过服务端数据预取和请求聚合提升首屏速度。
Q78: 数据库慢查询怎么排查?
答案:
先通过 slow log、APM、pg_stat_statements 或慢接口定位 SQL,再用 EXPLAIN/EXPLAIN ANALYZE 看执行计划。重点看是否全表扫、索引失效、扫描行数过大、排序临时表、JOIN 顺序和锁等待。
优化包括建复合索引、改写 SQL、避免函数包列、处理深分页、预聚合、分区归档和减少 N+1 查询。优化后要对比 P95/P99 和执行计划。
Q79: 前端监控 SDK 和埋点 SDK 有什么区别?
答案:
监控 SDK 关注错误、性能、接口、资源和环境,目标是定位问题;埋点 SDK 关注业务行为、点击、曝光、转化,目标是分析业务效果。
底层都有采集、缓冲、上报、降级,但数据模型和使用方不同。可以复用传输层,但语义要分开。
Q80: 你怎么设计前端日志?
答案:
日志要有等级、时间、模块、用户、traceId、上下文和错误栈。前端日志不能无限上报,要采样、限流和脱敏。
SDK debug 日志和线上监控日志要分开,前者帮助接入方调试,后者帮助平台定位问题。
Q81: Web Worker 你用来解决什么?
答案:
Web Worker 适合把计算密集任务移出主线程。凡科快图里,坐标变换、碰撞检测、边界判断、滤镜处理如果都放主线程,会影响拖拽和编辑体验。
配合 OffscreenCanvas,可以把部分绘制或图像处理也放到 Worker,提高 UI 响应。
Q82: Canvas 和 SVG 怎么选?
答案:
Canvas 适合像素级绘制、高频重绘和大量图元;SVG 适合矢量对象、文本、事件、图层和对象级编辑。
凡科快图从 Canvas 转向 SVG,是因为编辑器大量操作是对象级编辑,迁移后开发成本减少约 40%,可维护性更好。
Q83: 游戏或互动页面如何做资源加载优化?
答案:
资源要分层:首屏必需资源优先加载,非首屏资源懒加载,重复资源走缓存,大资源分包。加载过程要有进度、失败重试和降级提示。
如果接 Unity WebGL 或 H5 游戏,还要关注 wasm、纹理、音频、字体和 CDN 缓存策略。
Q84: 图片和媒体怎么优化?
答案:
使用合适格式,如 WebP/AVIF,按设备尺寸输出响应式图片,懒加载,预留尺寸防 CLS,CDN 压缩和缓存。视频音频要控制 preload,避免首屏加载所有媒体。
AI 对话和内容平台里,多媒体很多,必须按视口和用户行为加载。
Q85: 移动端适配你关注什么?
答案:
viewport、DPR、1px、软键盘、安全区域、滚动穿透、横竖屏、触摸事件、iOS/Android WebView 差异。布局上优先弹性布局、媒体查询和容器约束。
移动端问题很多不是框架问题,而是设备和容器差异,需要真实机型验证。
Q86: 浏览器兼容怎么做?
答案:
先确定目标浏览器和版本,配置 browserslist、Babel/PostCSS、polyfill 策略。新 API 先 feature detection,再决定是否降级。
SDK 更要保守,因为接入方环境不可控。不能假设所有宿主都和自己项目一样新。
Q87: 状态管理你怎么选?
答案:
组件内部状态用 useState/useReducer,跨组件少量共享用 Context,全局客户端状态用 Zustand/Redux/Recoil,服务端数据缓存用 SWR/TanStack Query。
核心原则是区分服务端数据和本地 UI 状态,避免全部塞进一个全局 store。
Q88: 请求层怎么封装?
答案:
请求层统一处理 baseURL、鉴权、超时、取消、重试、错误码、响应解包和日志。业务代码调用明确 API 函数,不散落 fetch/axios 细节。
配合 SWR/TanStack Query 时,还要设计 cache key、刷新策略和错误回退。
Q89: RESTful API 你怎么设计?
答案:
先明确资源模型,再设计 URL、方法、分页、过滤、排序、状态码、错误码和权限。创建用 POST,查询用 GET,更新用 PUT/PATCH,删除用 DELETE。
复杂动作可以用 action,但要保持语义清晰。接口稳定比一时方便更重要。
Q90: BFF 在前端架构里有什么价值?
答案:
BFF 可以把多个后端接口聚合成更贴近页面的数据结构,处理权限、缓存、降级和字段裁剪。对 SSR 页面尤其有价值,可以减少首屏请求瀑布。
我用 NestJS 做过多类中台服务,这种全栈视角能帮助前端更好地设计数据层。
Q91: Node.js 后端你做过什么?
答案:
我用 NestJS 做过 Prompt 模板管理、事件埋点、多语言文案、文件管理和配置中心。涉及 REST API、权限、缓存、数据库、OSS、Kafka、版本控制和定时报表。
这些不是 demo,而是生产级中台服务,能支撑前后端协同和业务复用。
Q92: Redis 在项目里怎么用?
答案:
主要用于热点缓存、临时状态、限流和多级缓存。Prompt 模板读取就是内存 60 秒、Redis 5 分钟、DB 兜底。
缓存要有失效策略、版本号和降级,不能只为了快而忽略一致性。
Q93: Kafka 在埋点系统里为什么需要?
答案:
埋点流量有峰值,如果直接写数据库会给数据库压力,也影响上报接口响应。Kafka 用来削峰解耦,服务端快速投递,Consumer 再批量写库。
后续要接实时计算、告警或数仓,也可以从 Kafka 扩展。
Q94: OSS 直传怎么设计?
答案:
前端先向后端申请临时上传凭证,后端鉴权后返回签名,前端直传 OSS。上传完成后回调业务服务保存元数据。
这样文件流量不经过业务服务器,安全和性能都更好。长期密钥不能暴露给前端。
Q95: Web3 钱包交互封装和 SDK API 有什么相似?
答案:
它们都要把复杂流程封装成稳定 API。钱包交互包含连接、签名、allowance、approve、gas 估算、发交易、确认和失败处理,业务如果到处写会很混乱。
统一封装后,业务只关心当前状态和下一步动作,底层细节由 SDK 处理。
Q96: 开发者体验你怎么提升?
答案:
从接入、调试、文档、类型、错误、示例和升级全链路提升。比如提供快速开始、TS 类型、debug 面板、错误码文档、常见问题、示例项目和迁移指南。
开发者体验好不好,取决于接入方第一次失败时能不能自己定位问题。
Q97: 技术文档你怎么写?
答案:
我会先写给目标读者,而不是写给自己。SDK 文档偏接入路径,架构文档偏设计取舍,排障文档偏步骤和检查项。
文档要有代码示例、边界、错误码和版本说明。复杂系统还要有流程图和时序图。
Q98: 如何组织技术分享?
答案:
我会选团队真实痛点,比如 SDK 接入、性能排查、AI 工具、Monorepo 规范。分享不是炫知识,而是让大家会用、能复用。
分享后最好沉淀为文档、模板、脚手架或 checklist,否则影响很快会消失。
Q99: Code Review 你关注什么?
答案:
关注正确性、边界、可维护性、性能、安全、测试和是否符合架构边界。格式问题交给工具解决。
对初中级同学,Review 还要解释为什么,帮助他们成长,而不是只给结论。
Q100: 你怎么指导初中级开发?
答案:
先给清晰任务边界和验收标准,再通过方案评审和代码 review 帮他们建立判断力。复杂任务拆成小阶段,让他们能逐步承担。
我会鼓励他们写文档、做复盘和分享,把个人经验变成团队知识。
Q101: 团队技术规范怎么落地?
答案:
规范要工具化。ESLint、Prettier、TypeScript、commitlint、CI 检查、模板和脚手架,比口头约定更可靠。
规范也要解释原因,让大家知道它解决什么问题。否则规范会变成负担。
Q102: 如何推动新技术落地?
答案:
先找真实业务问题,再做 PoC 验证收益和风险。小范围试点后沉淀最佳实践,再推广到更多项目。
我不会因为技术新就推动,必须能提升效率、体验、性能或稳定性。
Q103: 技术决策有分歧怎么办?
答案:
先把分歧转成评估维度,比如性能、成本、风险、可维护性、团队熟悉度。必要时用 PoC 和数据判断。
如果没有绝对答案,就选择当前约束下最合适的方案,并记录原因,后续可以复盘调整。
Q104: 与产品和设计怎么协作?
答案:
需求阶段我会确认用户目标、边界和优先级;设计阶段确认交互状态、异常态、动效和响应式;开发阶段及时同步风险和取舍。
技术不是只负责实现,也要帮助产品和设计理解成本、风险和体验边界。
Q105: 与后端怎么协作?
答案:
提前对齐数据模型、接口契约、错误码、权限、缓存和兼容策略。复杂页面要明确哪些数据前端聚合,哪些后端聚合。
我自己做过 NestJS 后端,所以能更好地理解后端约束,沟通会落到具体接口和数据结构。
Q106: 与运营怎么协作?
答案:
运营关注配置效率、活动效果和数据反馈。中台系统要让他们能安全地配置、预览、发布和回滚,同时提供数据看板和操作审计。
比如 Prompt 模板、配置中心、多语言和埋点平台,本质上都是让运营或业务方更低成本地完成工作。
Q107: 你怎么证明有从 0 到 1 能力?
答案:
Prompt 模板管理系统、事件埋点分析系统、多语言文案管理、配置中心都是从需求、方案、前后端实现、灰度到上线的完整链路。它们不是单页面功能,而是平台型能力。
我能从业务痛点出发,抽象模型、设计架构、做核心实现,再推动团队接入和沉淀文档。
Q108: 你怎么平衡业务交付和平台化?
答案:
不会一开始就做大而全平台。先解决最高频、最痛、收益明确的问题,做最小可用能力;在两个以上真实场景验证后,再抽象成平台。
Prompt 模板系统就是先解决编辑、变量、调试、SDK,再逐步补审批、灰度和评估。
Q109: 如何处理技术债?
答案:
先分类:稳定性风险最高,影响开发效率次之,体验和结构问题再排。处理方式是结合业务迭代逐步偿还,而不是为了重构而重构。
虎牙 SSR 重构就是典型技术债治理,通过渐进迁移和灰度控制风险。
Q110: 如果让你入职后前三个月做规划,你会怎么做?
答案:
第一个月熟悉业务、SDK 平台现状、Next.js 架构、接入方痛点和线上问题。第二个月选择一个高收益方向落地,比如 SDK debug 面板、接入文档重构、数据上报链路监控或 Monorepo 包治理。第三个月扩大到多业务线,沉淀规范、模板、指标和最佳实践。
我会先用可量化效果证明价值,再推动更大范围的工程化建设。
Q111: 如果面试官问你没有游戏经验怎么办?
答案:
我会诚实说没有大型游戏前端项目经验,但我有与游戏接入高度相关的能力:H5/WebView、实时通信、数据上报 SDK、PWA 缓存、性能优化、Canvas/SVG 复杂交互、Web Worker、跨端调试。
游戏接入里很多工程问题是加载、通信、性能、兼容和监控,这些我有可迁移经验。真正游戏业务规则可以通过团队场景快速补齐。
Q112: 如果面试官问你 App Router 经验够不够怎么办?
答案:
我会说我有 Next.js 项目经验和 SSR 实战,App Router 的核心机制也熟悉,包括 Server Components、layout、loading、error、Route Handler、缓存和 Streaming。即使项目版本不同,底层问题仍是数据获取、渲染模式、缓存和性能。
如果团队已经深度使用 App Router,我能很快按项目规范接上,并在缓存、SEO、性能和稳定性上发挥经验。
Q113: 如何设计一个 SDK 平台的控制台?
答案:
控制台要包含应用管理、密钥/凭证、版本管理、接入指南、事件或接口定义、调试日志、调用统计、错误监控、告警和文档。接入方能看到自己的 appId、环境、版本、调用量、错误率和最近上报。
平台不只是发 SDK 包,还要让接入方能自助接入、自助排查、自助升级。
Q114: SDK 平台如何做多租户?
答案:
每个业务线或应用有独立 appId、环境、配置、权限和数据隔离。服务端按 appId 鉴权和限流,查询和看板也按租户隔离。
多租户最重要的是权限和数据隔离,不能因为一个业务接入错误影响其他业务。
Q115: SDK 平台如何做限流?
答案:
按 appId、用户、IP、事件类型或接口维度限流。普通上报可以令牌桶或滑动窗口,高风险接口要更严格。超过限流后返回明确错误,并在 SDK 侧做退避重试或采样降级。
限流要配合监控,让平台知道哪个接入方异常增长。
Q116: SDK 平台如何做调度机制?
答案:
调度可以理解为任务、上报、重试、批处理和优先级管理。前端 SDK 有队列和批量触发,服务端有 Kafka 缓冲和 Consumer 批量写入,失败进入重试或死信队列。
对于不同事件可以有优先级,关键事件优先上报,低价值曝光事件在弱网或限流时可以采样或丢弃。
Q117: SDK 平台如何做可观测性?
答案:
要有接入方维度、版本维度、环境维度的指标:调用量、成功率、错误率、延迟、丢弃数、重试数、队列长度、缓存命中率。日志要带 traceId,方便从前端请求追到服务端和数据库。
可观测性做好后,SDK 问题才能从“用户说不行”变成“哪一段、哪个版本、哪个业务线出了问题”。
Q118: SDK 平台如何做回滚?
答案:
如果是 npm 包,回滚通常是业务回退版本;如果是托管脚本,可以平台侧把版本指针切回旧版本。服务端配置也要版本化,支持快速回滚。
回滚必须提前设计,不能等事故发生才想办法。每次发布都要有对应的监控指标和回滚路径。
Q119: 如果面试官让你总结核心优势,你怎么说?
答案:
我的核心优势是前端架构、SDK 平台和全栈工程化结合得比较紧。前端上能做 Next.js、React、SSR、PWA、性能和复杂交互;SDK 上做过埋点、Prompt、实时通信和钱包封装;全栈上能用 NestJS、数据库、Redis、Kafka 打通数据链路;团队上也做过负责人、方案评审、Code Review 和技术沉淀。
所以我适合这个岗位,是因为它需要的不只是页面开发,而是 SDK API、开发者体验、稳定性、性能和团队工程化的综合能力。
Q120: 你有什么想问面试官的问题?
答案:
我会问三个方向。第一,当前 SDK 平台最主要的接入方是谁,内部业务还是外部开发者?第二,现在最大的痛点是 API 设计、接入效率、稳定性、数据上报,还是文档和调试体验?第三,Next.js 和 Monorepo 当前建设到什么程度,团队希望我入职前三个月优先解决什么问题?
这些问题能帮助我判断岗位真实优先级,也体现我关注落地效果。
SDK 深挖追问
Q121: SDK API 设计时,怎么判断一个参数应该放初始化配置还是调用参数?
答案:
我会看它的变化频率和作用范围。全局稳定、影响 SDK 行为的参数放初始化配置,比如 appId、env、debug、transport、采样率、默认超时。每次调用都可能不同的参数放调用参数,比如事件属性、业务上下文、请求 payload。
如果一个参数既有全局默认值,又允许单次覆盖,可以设计成“全局配置 + 调用覆盖”,调用参数优先级更高。这样 API 既简单,又不牺牲灵活性。
Q122: SDK API 如何避免越做越碎?
答案:
我会避免为每个业务场景加一个新方法,而是抽象稳定模型。比如埋点 SDK 不应该有 trackButtonClick、trackBannerShow、trackPaySuccess 这种无限增长的方法,而是统一 track(eventName, properties),事件差异通过事件定义平台和类型约束解决。
API 变碎通常说明抽象层级不对。SDK 主 API 要少而稳定,业务差异通过配置、插件、事件定义和扩展字段表达。
Q123: SDK 如何设计事件总线?
答案:
事件总线用于连接核心流程和插件。核心会在生命周期节点发事件,比如 init、ready、beforeSend、afterSend、error、flush、destroy。插件订阅这些事件,实现扩展逻辑。
事件总线要注意三点:第一,事件类型和 payload 要有 TypeScript 类型;第二,插件异常要隔离,不能中断主流程;第三,事件触发顺序要稳定并写入文档,否则插件之间会互相踩。
Q124: 插件生命周期怎么设计?
答案:
我会给插件定义 setup、start、stop、destroy 四个阶段。setup 注册 hooks 和读取配置;start 执行需要运行时环境的逻辑,比如监听路由和 DOM;stop 暂停采集或发送;destroy 清理定时器、事件监听和缓存。
插件必须可卸载,否则 SPA 长时间运行或微前端场景下容易内存泄漏。插件 API 还要支持依赖声明,比如性能采集插件依赖传输插件先初始化。
Q125: 插件之间有依赖关系怎么处理?
答案:
插件 manifest 里声明 name、version、dependencies 和 order。SDK 初始化时先构建依赖图,拓扑排序后再执行。发现循环依赖或缺失依赖时,在开发环境明确报错,生产环境跳过问题插件并上报。
如果依赖只是可选能力,不要硬依赖,可以通过 capability detection 判断,比如有 storage capability 就做离线缓存,没有就降级内存队列。
Q126: SDK 如何设计“能力检测”?
答案:
能力检测不是只判断浏览器版本,而是判断具体 API 是否可用。比如 navigator.sendBeacon、fetch、AbortController、IndexedDB、ResizeObserver、BroadcastChannel 都要按能力检测。
检测结果形成 capability map,后续 transport、storage、scheduler、debug panel 都按 capability 选择 adapter。这样 SDK 不需要写一堆散落的 if else,也方便在调试面板里展示当前环境为什么走了某个降级路径。
Q127: SDK 调试面板应该展示哪些信息?
答案:
我会分几块展示:基础信息(SDK 版本、协议版本、appId、env、userId 脱敏)、运行环境(浏览器、WebView、能力检测结果)、队列状态(待发送数、失败数、重试数、采样数)、最近请求(payload、状态码、耗时、错误码)、插件状态(是否启用、异常次数)、配置快照和日志。
调试面板要支持导出诊断包,接入方反馈问题时直接发诊断包,比截图和口头描述可靠得多。
Q128: SDK 的诊断包怎么设计?
答案:
诊断包是一个脱敏 JSON,包含 SDK 版本、初始化配置摘要、能力检测结果、最近 N 条内部日志、最近 N 次请求、队列状态、插件状态、错误堆栈和 traceId。敏感字段如 token、手机号、邮箱、用户输入要脱敏或不导出。
诊断包的价值是让平台方快速复现和定位问题。它应该可以通过 debug 面板一键复制,也可以在用户授权后自动上传到排障系统。
Q129: SDK 如何做采样?
答案:
采样要按场景区分。性能监控可以按用户或会话采样,保证同一个 session 内链路完整;高频曝光事件可以按事件维度采样;错误事件通常不采样或低采样,避免漏掉问题。
采样策略最好由服务端配置下发,支持按 appId、版本、环境、用户分组动态调整。SDK 每次丢弃事件也要记录采样原因,避免排查时误以为丢数据。
Q130: SDK 如何做离线缓存和重放?
答案:
前端先把失败事件放内存队列,如果网络断开或页面即将关闭,可以落 IndexedDB。网络恢复后按时间顺序批量重放。重放要有最大保留时间、最大条数、最大重试次数,避免无限堆积。
不是所有事件都值得离线缓存。支付成功、关键转化这类事件优先级高;普通曝光可以在弱网下采样或丢弃。SDK 要支持事件优先级。
Q131: SDK 如何保证事件顺序?
答案:
首先每条事件带 client timestamp 和 sequence id。内存队列按 sequence id 递增发送,失败重试时尽量保持原顺序。服务端入库时同时保存客户端时间和服务端接收时间。
但分布式系统里不能绝对依赖客户端顺序,页面多标签、离线重放、时钟不准都会影响顺序。所以分析侧要明确排序依据,关键流程事件可以带 sessionId 和 traceId 还原链路。
Q132: SDK 如何避免重复上报?
答案:
每条事件生成 eventId,服务端以 appId + eventId 做幂等去重。前端重试时复用同一个 eventId,不重新生成。对于页面曝光这类事件,SDK 还可以在同一页面生命周期内做去重策略,比如同一元素在短时间内只上报一次。
重复上报不可完全避免,所以服务端必须有幂等能力。只靠前端去重不可靠。
Q133: SDK 如何做请求重试?
答案:
重试要看错误类型。网络错误、5xx、超时可以指数退避重试;4xx 参数错误通常不重试,直接记录错误;限流错误要按服务端返回的 retry-after 延迟。重试次数要有限制,并加入 jitter,避免大量客户端同时重试形成峰值。
对于批量上报,部分失败时要看服务端是否支持逐条结果。如果支持,就只重试失败项;如果不支持,就整批重试但依赖 eventId 去重。
Q134: SDK 如何设计 flush 机制?
答案:
flush 是把队列里的数据立即发送出去。触发场景包括达到批量阈值、时间阈值、页面切后台、页面卸载、用户主动调用、SDK destroy。flush 要返回 Promise,让业务在必要时等待完成。
页面卸载时不能依赖普通异步请求完成,所以优先 sendBeacon。flush 还要防止并发,多次 flush 同时触发时应该合并或排队。
Q135: SDK 如何做多标签页协调?
答案:
多标签页会带来重复初始化、重复上报、离线队列竞争。可以用 BroadcastChannel 或 storage event 做标签页通信,选出一个 leader 负责某些全局任务,比如定时 flush;其他 tab 只写队列或发送本页事件。
但多标签协调会增加复杂度,不是所有 SDK 都需要。只有全局状态明显冲突时才做,否则保持每个 tab 独立更简单可靠。
Q136: SDK 如何处理隐私和数据脱敏?
答案:
首先事件定义层面就要限制敏感字段,避免业务随意上传手机号、邮箱、身份证、token。SDK 可以提供字段黑名单和正则脱敏,比如命中 token、authorization、phone 这类 key 时自动脱敏或拒绝发送。
其次 debug 日志和诊断包也要脱敏。隐私不是服务端才处理,SDK 作为数据入口必须前置防护。
Q137: SDK 如何处理 source map 和线上错误定位?
答案:
SDK 构建时生成 source map,但不要公开暴露给所有用户。发布时把 source map 上传到错误平台,线上错误通过版本号和 commit hash 还原堆栈。
SDK 包要在错误上报里带 sdkVersion、buildId、commitSha,这样平台能准确匹配 sourcemap。否则压缩后的堆栈很难定位。
Q138: SDK 如何做兼容性测试?
答案:
我会做三层测试。单元测试覆盖核心逻辑,比如队列、重试、采样、协议解析;浏览器集成测试覆盖 Chrome、Safari、Firefox、移动 WebView;真实接入示例测试覆盖 React、Next.js、Vue、普通 script 标签。
SDK 的兼容性不是只看自己 demo 跑通,而是要覆盖主要宿主环境。每次发布前至少跑一轮 smoke test。
Q139: SDK 如何设计 ESM、CJS、UMD 多产物?
答案:
现代构建通常提供 ESM 给 bundler 做 tree shaking,CJS 兼容 Node 或旧工具链,UMD/IIFE 给 script 标签直接引入。package.json 里通过 exports、module、main、types 明确入口。
还要注意 sideEffects 标记,避免 tree shaking 把有副作用的初始化代码误删。托管脚本版本要带 SRI 或版本 hash,方便缓存和安全校验。
Q140: SDK 如何做破坏性升级?
答案:
破坏性升级要分阶段。第一阶段发布兼容层,新旧 API 都支持,旧 API 打 warning;第二阶段发布迁移指南、codemod 和示例;第三阶段统计旧 API 调用量,推动业务迁移;第四阶段 major 版本移除旧 API。
如果 SDK 面向多个业务线,不能只发一封通知就结束。要有版本看板,明确哪些业务还没升级,必要时提供自动 PR 或脚手架迁移。
Q141: npm SDK 和托管 script SDK 怎么取舍?
答案:
npm SDK 适合工程化项目,接入方可以通过 bundler tree shaking、类型提示和版本锁定获得更好开发体验;缺点是升级需要发版。托管 script SDK 适合低门槛接入,复制一段脚本即可使用,平台可以控制版本和灰度;缺点是缓存、兼容和安全要求更高。
如果面向内部 React/Next.js 项目,我优先 npm 包;如果面向外部开发者或低代码/运营页面,我会同时提供 script 版本。两套产物底层复用核心包,只是入口和加载策略不同。
Q142: 托管 script SDK 的加载策略怎么设计?
答案:
脚本要支持 async/defer,不能阻塞页面首屏。常见方式是给接入方一段 bootstrap snippet,先创建队列缓存用户早期调用,真实 SDK 加载完成后再 replay 队列。
脚本 URL 要带明确版本,比如 /sdk/v1.2.3/index.min.js,也可以提供 /sdk/latest.js 给低风险场景。生产环境我更推荐固定版本,避免平台升级影响所有接入方。
Q143: script SDK 如何处理加载失败?
答案:
bootstrap 阶段要设置超时,如果主 SDK 加载失败,就进入降级状态:队列不再无限增长,关键调用返回明确错误,非关键调用丢弃或缓存。还可以提供备用 CDN 域名,首域名失败后切换。
调试上要能区分是 DNS、CDN、CSP、网络超时还是浏览器拦截。否则接入方只会看到“SDK 没生效”,排查成本很高。
Q144: SDK 的开发者门户应该有哪些能力?
答案:
开发者门户至少包含应用创建、appId/密钥管理、环境配置、快速接入、API 文档、在线调试、版本列表、调用统计、错误日志、告警配置、工单反馈和迁移指南。
如果是数据上报 SDK,还要有事件定义、属性校验、实时上报查看和数据质量报告。好的门户能让接入方自助完成 80% 问题,不需要每次找平台团队。
Q145: SDK 平台的 API Key / appId 鉴权怎么设计?
答案:
前端公开环境只能放 appId,不能放 appSecret。appId 用来识别应用和加载配置,真正高权限操作必须走后端签名或临时 token。服务端按 appId 校验来源、环境、配额和权限。
如果是外部开发者平台,要支持密钥轮换、禁用、环境隔离和调用审计。密钥泄露时可以快速吊销,不影响其他应用。
Q146: SDK 平台的 SLA/SLO 你会怎么定义?
答案:
SLO 要按能力定义,比如 SDK 静态资源可用性 99.9%、上报接口成功率 99.9%、P95 延迟小于 200ms、数据入库延迟 P95 小于 1 分钟、调试日志查询延迟小于 5 秒。
有了 SLO 才能设计告警和优先级。比如上报成功率低于阈值要立刻告警,普通 debug 查询慢可以低优先级处理。SDK 平台不能只看功能是否能用,还要看可用性指标。
Q147: SDK 兼容性矩阵怎么做?
答案:
兼容性矩阵要列出浏览器、系统、WebView、框架、构建工具和加载方式。比如 Chrome/Safari/Firefox、iOS/Android WebView、Next.js SSR、React/Vue、Webpack/Vite、npm/script。
每次发布前跑核心矩阵的 smoke test,文档里也要明确最低支持版本。对于不支持的环境,要在初始化时给清晰提示,而不是运行到一半才报错。
Q148: iframe 消息协议如何做版本演进?
答案:
协议版本要在握手阶段协商。父页面和 iframe 各自声明支持的 protocolVersions 和 capabilities,双方选择最高兼容版本。新增字段要保持可选,新增消息 type 要让旧版本可以忽略。
如果必须 breaking change,就引入新 major 协议,比如 v2。平台要同时支持 v1 和 v2 一段时间,并通过控制台展示哪些接入方还在用旧协议。
Q149: iframe 通信如何处理大数据传输?
答案:
postMessage 不适合频繁传大对象。大数据可以传引用,比如文件 ID、URL、任务 ID,让接收方再按需拉取。必须传大数据时,可以分片传输,带 chunkId、total、checksum,接收方组装后校验。
对于 ArrayBuffer 这类数据,可以用 Transferable Objects 减少拷贝。但大多数业务场景更推荐“消息传控制,数据走接口”。
Q150: iframe 通信如何做超时和取消?
答案:
请求响应类消息都要有 timeout。发送方维护 pending map,超时后 reject,并发送 cancel 消息给对方,让对方可以清理任务。响应回来时如果 pending 已不存在,就丢弃。
如果一个请求会触发长任务,比如文件处理或游戏加载,可以设计 progress、cancel、complete、error 四类消息,避免用户不知道当前状态。
Q151: SDK 服务端配套一般包括什么?
答案:
SDK 平台不是只有前端包,通常还要有配置服务、鉴权服务、上报接入服务、日志服务、调试查询服务、版本管理服务和告警服务。前端 SDK 负责采集和调用,服务端负责治理、校验、存储和观测。
我做埋点系统和 Prompt SDK 时都有这个体会:SDK API 只是入口,真正稳定依赖背后的服务能力。
Q152: SDK 的配置下发怎么做?
答案:
SDK 初始化时按 appId、env、sdkVersion 拉取配置,配置包含采样率、上报地址、插件开关、灰度策略和限流参数。配置要有版本号、缓存时间和签名,防止中间人篡改。
读取策略可以是启动拉取 + 本地缓存兜底。配置接口失败时使用最近一次可用配置,不能让 SDK 因配置服务短暂异常完全不可用。
Q153: SDK 如何处理多环境?
答案:
至少区分 development、staging、production。不同环境的 appId、上报地址、采样率、日志等级、debug 权限要分开。生产环境默认关闭详细日志,测试环境打开更多校验。
多环境的关键是避免串数据,测试数据不能进入生产看板,生产密钥不能出现在测试页面。
Q154: SDK 如何做灰度配置下发?
答案:
灰度维度可以是 appId、用户 hash、地区、版本、环境、业务线。服务端根据规则返回不同配置,SDK 只执行结果,不在前端暴露复杂策略。
配置要带灰度命中信息,debug 面板里显示“为什么当前用户命中了这个配置”。这样灰度问题才能被接入方和平台方共同定位。
Q155: SDK 如何处理宿主框架差异?
答案:
核心 SDK 不绑定框架,提供 vanilla client;React/Vue/Next.js 只做薄封装,比如 Provider、hook、plugin。这样宿主框架升级不会影响核心能力。
Next.js 要特别注意 SSR 边界,React hook 只能在客户端使用;Vue 插件要提供 install 方法;普通 script 标签要暴露全局对象。这些入口可以不同,但底层协议和核心逻辑要一致。
Q156: SDK 如何做端到端链路追踪?
答案:
前端 SDK 生成 traceId,每次请求或上报都带上,服务端日志、Kafka 消息、数据库记录都保留同一个 traceId。排查问题时可以从前端日志一路查到服务端和入库记录。
如果接入方已经有自己的 traceId,SDK 应支持透传或合并,避免多个链路 ID 割裂。
Q157: SDK 如何避免内存泄漏?
答案:
要关注定时器、事件监听、DOM 引用、队列、pending promise 和插件资源。SDK 必须提供 destroy 方法,清理所有监听、定时器和队列引用。SPA 路由切换或微前端卸载时要调用 destroy。
调试面板可以显示当前监听器数量、队列长度和插件状态,帮助发现泄漏迹象。
Q158: SDK 如何处理 SSR + CSR 双端重复上报?
答案:
SSR 阶段通常不应该上报用户行为,只做服务端日志或性能记录。客户端 Hydration 后再初始化行为 SDK。对于页面曝光这类事件,要确保只在客户端上报一次,可以用 hydration 标记和 eventId 去重。
如果服务端和客户端都需要记录同一页面访问,要在事件模型里区分 server_view 和 client_view,避免分析口径混乱。
Q159: SDK 如何做自动化发布流水线?
答案:
流水线包括 lint、typecheck、unit test、browser test、build、size check、changelog、version、publish、sourcemap upload、文档发布和示例项目 smoke test。任何一步失败都不能发布。
发布后还要自动创建版本记录,监控新版本错误率和接入量。如果错误率异常,触发回滚或标记该版本不可用。
Q160: 如果让你接手一个混乱的 SDK 平台,你先做什么?
答案:
我会先做现状盘点:有哪些 SDK、哪些版本、哪些业务在用、核心 API 是什么、线上错误率和调用量如何、有没有文档和调试能力。然后按风险排序,优先补监控、版本看板和接入文档,因为这些能最快降低维护成本。
接着再治理 API、插件、配置、发布和兼容策略。混乱平台不能一上来重写,先让问题可见,再逐步收敛。