← 返回资料库
面试准备 / PERSONAL ARCHIVE

四周求职与面试准备计划

一份文档完成四周准备:简历经历、自我介绍、项目讲述、技术问答、手写练习、投递与复盘。

更新于 2026.09.11指南#求职计划#面试#每周行动#BBDbuy

2026-09-11 按本人要求制定的建议初稿。每周可用时间、目标岗位和开始日期尚未确认;以下安排不是已经接受的日程,也不代表已经完成任何投递或面试。现有简历和示例周计划保持原样。

这四周先做到什么

把“已有简历和项目材料”推进到“能讲清两个真实案例、能回答相关基础题、开始有针对性地投递并复盘”。四周是第一轮准备周期,不是拿到 offer 的期限;年度跳槽目标仍以本人原有意向为准。

暂按 React / TypeScript 为主、兼顾 React Native 来组织。本页已融入现有简历、项目讲述、基础与手写题,日常准备只需打开本页。四周完成主线;按岗项目卡和补充手写题用来替换当天练习或留到下一轮,不要求八小时学完全部材料。

一页使用地图

今天要做什么 在本文找哪里 结束时留下什么
看自己有哪些经历 简历经历底稿 标出能独立解释的经历和待核实项
第 1 周准备 W1 自我介绍与三端架构 一段录音、一张分层图
第 2 周准备 W2 请求治理与支付轮询 请求案例、一次轮询练习
第 3 周准备 W3 购物车与 React 状态表、一次模拟面试
第 4 周准备 W4 按岗项目卡与求职问答 选两张项目卡,修正最主要的缺口
遇到基础题或手写题 基础速查与补充手写练习 先独立回答,再对照要点
准备投递或面试 投递、模拟与复盘 一条真实记录和下一步

简历经历底稿

以下为现有简历的压缩整理,帮助回忆和组织回答,不是新核实的个人事实。推荐回答均为练习草稿;“主导、独立、负责”的程度最终按真实参与替换。

简历项目 业务与技术 面试时可以展开的职责
BBDbuy 三端 海外代购与国际集运;Next.js、React、RN/Expo、TypeScript、Query、Zustand 三端 Monorepo、共享 Flow、SKU、结算支付、聊天、RN 稳定性、深链、CI/CD 与商店发布
BBDbuy 运营后台 采购、仓储、财务、客服、运营;React、Umi Max、Ant Design、ECharts 仓储履约、Code 128 条码、客服组件、退款审核、批量导出、作业看板
BBD 仓库小助手 Android PDA;Vue 3、uni-app、TypeScript 条码驱动业务、useScanner/useSubmit、影像上传、弱网反馈、WGT 更新
新智慧 TMS 跨境物流 SaaS;React、Umi、Ant Design、MobX、Handsontable 业务页面、配置表格、批量录入、合同/PDF、国际化、PDA WebView 联调
Manifest V3 扩展 采购人员使用的浏览器工具 跨页面订单及 SKU 匹配、物流单号采集与回填,人工确认

现有简历还记载:包包达公司首名前端、后续团队扩充至 3 人、前端方向负责人。准备一个真实的协作或交付决策来说明这些职责,不能只报头衔。本地三端仓库不自动证明后台、PDA、扩展和团队管理的所有个人贡献。

教育口径来自现有简历:广东白云学院软件工程本科(2020.09—2022.06);深圳信息职业技术学院软件技术大专(2017.09—2020.06)。个人档案中“学历未知”等旧描述尚未同步,这里按已提供简历记录,不延伸推断实习或工作时间。

投递前必须统一的口径

项目 现有记录 本次处理方式
工作年限和公司时间 简历写 5 年以上、2021.04 开始、2024.04 入职包包达;个人档案记 2022 年开始、2025.04 第三份工作 核实实习/转正及各段起止,不自行选一组或拼接年限
项目开始时间 简历把后台/PDA 写为 2024.04 起;旧面试材料出现 2025.08 公司入职与具体项目启动分开核实
平台规模 简历写 7 万+客户、10 万+有效订单、1.6 万+运单、近期日单 3000~4000 核实统计日期、有效口径及累计/单日区别;不说成个人带来的增长
后台与 TMS 规模 简历写后台 10+ 模块、50+ 页面;TMS 89 页面;某日 12 人完成 4000+ 上架任务 是简历中的项目规模或单日样例,不等于个人完成量和长期均值
个人成果 三端主要建设及请求层本人参与有记录;其他细节需能举例 没有测量证据不加效率、复用率、崩溃率百分比

三端语言资源在本次本地阅读中可见 7 种;RN 当前依赖可见 Expo 56、RN 0.85、NativeWind 4。版本现状不能单独证明全部升级过程和线上效果。

准备时怎样使用简历

每条要点写成“业务问题 → 我的职责 → 一个关键选择 → 验证方式 → 实际结果”。不能独立解释的细节先记为缺口;不要把练习答案当成自己已经做过的事情。

公共请求层尚未单列在现有简历,可作为待核实职责后的补充表达:

建设三端公共请求层,以平台无关 Client 与端侧 Transport 隔离差异,统一响应协议、错误分类和 required 401 会话处理,并结合 Query 管理读取取消、有限重试及错误反馈边界。

这只是本页候选表述,原简历版本未被覆盖。

每周怎么安排

每周建议 120 分钟:25 + 25 + 40 + 30,分四次完成。自己选择有精神的时段,不固定早起、深夜或休息日;休息日的长时段也可以拆开。

时段 建议用时 做法
A:梳理 25 分钟 选一个问题,对照经历或代码写要点
B:表达 25 分钟 先不看资料回答,再查漏补缺
C:实练 40 分钟 项目追问、最小代码练习或模拟面试
D:求职 30 分钟 筛岗位、投递或复盘,留下下一步

先试一周,再根据实际耗时调整。有正式面试时,直接用面试和复盘替换本周练习,额外耗时如实记录,不再叠加任务。

四周计划表

下表中的数量是建议上限附近的行动目标,不是必须凑齐的指标。没有匹配岗位时不为凑数投递。

周次 A · 25 分钟 B · 25 分钟 C · 40 分钟 D · 30 分钟
第 1 周:准备开口 核对工作时间线;写下求职条件 录一次 60 秒自我介绍 梳理 BBDbuy 三端架构,录一次 3 分钟讲述 筛 3 个岗位;事实核对后可先投 1 个
第 2 周:一个深入案例 公共请求层:旧问题、分层、取舍 回答 401、取消、读取重试三个问题 手写可停止的异步轮询,解释异常与清理 定向投递 2~3 个岗位;记下要求差异
第 3 周:第二个案例 购物车状态与写入后回源 练 React 状态、Effect、闭包追问 做一次 25 分钟模拟面试,15 分钟复盘 投递 2~3 个岗位;查看已有沟通进展
第 4 周:按反馈修正 只补最影响回答的两个缺口 练离职原因、个人贡献与 AI 协作 再模拟一次;对比两次回答的变化 复盘投递与面试,决定下一轮重点

每周完成到什么程度

  • 第 1 周:有一份已核对或明确标注待核实的时间线、一段 60 秒自我介绍、一张架构讲述提纲和 3 条岗位记录。未核实的日期不直接选一组写进投递版。
  • 第 2 周:不看稿能讲清公共请求层“为什么改、自己做什么、怎么验证”;轮询代码能说明正常结束、失败和取消,无法独立写出的部分记入缺口。
  • 第 3 周:能用一个购物车例子区分服务端数据、选择与编辑状态、提交状态;完成一次录音或对话模拟,留下最重要的 3 个问题。
  • 第 4 周:有两次可比较的模拟记录、更新后的项目提纲和投递记录;根据实际反馈选出下一轮最需要补的两项,不要求题库全部过完。

第 1 周可直接勾选的执行单

开始日期:________  本周实际可用时间:________

完成 任务与产物 预计用时
核对开始工作、实习/转正、各公司起止月份;标明仍不确定的项 15 分钟
写下岗位方向、薪资口径、休息安排、通勤的期望与底线 10 分钟
录 60 秒自我介绍;回听后只改最不清楚的两句话 25 分钟
用“问题→职责→方案→验证→结果”写架构提纲,并讲 3 分钟 40 分钟
记录 3 个岗位各自的匹配点与缺口;核实简历事实后试投 1 个 30 分钟

本周实际完成:________________________________________________

最卡住的一件事:______________________________________________

下周只调整一件事:____________________________________________

W1 自我介绍与三端架构

对应简历: 职业概述、BBDbuy 三端架构、Monorepo、API / Query / Flow / Types。

A:核对简历与岗位条件,25 分钟

前 15 分钟完成上方口径表,后 10 分钟填本文末尾求职条件表。最先处理日期、个人职责和成果来源,不在这里花时间调整简历配色。

B:60 秒自我介绍,25 分钟

下面是根据已有材料写的练习稿,实际使用时删除不符合本人职责的句子:

面试官您好,我叫张育华,主要使用 React 和 TypeScript,做过跨境电商 PC、H5、React Native,以及运营后台和仓库 PDA。目前主要项目是 BBDbuy,我承担了多端项目的主要建设工作,也借助 Codex 推进开发和工程改进。

最近的重点是三端业务复用和请求治理:把一致的业务规则沉淀到公共 API、Query 和 Flow,由各端适配路由、存储及交互差异。我希望重点介绍其中的状态边界、错误处理和复杂交易流程,也可以展开 RN 与发布相关经历。

时间线未统一前,不在练习稿里新增精确年数。练习时先录一次,回听后只修正两处:听不懂的术语、没有说明自己做什么的句子。

C:三分钟项目讲述,40 分钟

先讲业务: BBDbuy 面向海外用户做代购和国际集运。业务从商品/SKU、购物车、结算支付,到入库验货、合箱、国际运单和售后客服。三端面对的是相同业务,但页面和平台能力不同。

再讲难点: 同一规则如果在 PC、H5、RN 分别实现,修改和验证容易不一致;直接共享页面又会把 DOM、原生能力和路由耦合在一起。

讲自己的方案: 结合真实职责说明如何推进 Monorepo,如何选择抽取边界,以及如何逐步让三端接入。一个可用的讲述骨架是:

我把工程组织和业务复用分开处理。pnpm Workspace 与 Turborepo 管理依赖和构建;公共包按 API、Query、Flow 和类型分层。API 描述接口,Query 管服务端缓存,Flow 编排动作;页面展示和 Next/Expo 能力留在 App,通过 Adapter 注入。共享的是规则,平台交互继续独立实现。

例如购物车数量、备注和结算需要一致的业务规则,但 PC 的弹窗、H5 的路由、RN 的原生确认不同。公共 Flow 通过最小回调使用这些能力,避免再维护三份状态流程。结果可以用具体模块的接入、错误处理和测试说明;没有统计过的效率提升不报数字。

页面与端侧 Adapter
  → 公共 Flow:选择、校验、动作编排
  → Query:缓存、读取、写入与失效
  → API:业务接口及合同
  → Request Client / Transport

Runtime:注入 request、auth、feedback
Domain Port:注入特定流程的导航、支付、相机等能力
面试追问 回答要点
Monorepo 等于业务复用吗? 不等于。它组织代码与任务;业务分层和适配边界才决定能否复用
为什么不用一个大 Hook? 接口、缓存、编排和 UI 生命周期不同;按职责拆分,避免页面同时拥有所有状态
所有东西都抽公共包吗? 只抽规则一致、输入输出稳定、平台差异可注入的能力;单端交互留在 App
这是六边形架构吗? 更准确是模块化 Monorepo、业务分层,借鉴 Ports and Adapters;业务仍依赖 React/Query
怎么证明迁移有效? 选一个真实模块,展示原问题、各端接入、关键回归和遗留边界;不靠目录数量证明
三端 UI 全复用了吗? PC/M 可共享 Web 表现组件;RN UI 独立,通过公共业务能力保持规则一致

40 分钟分配:10 分钟整理五行提纲,10 分钟画分层,10 分钟回答三个追问,10 分钟录音并改一处。完成标准: 不看稿能说明每层负责什么,并举出一个实际边界。

D:筛选岗位,30 分钟

找 3 个实际岗位,把“岗位要求 → 对应简历证据 → 缺口”各写一行。基础事实核实后可先投 1 个,不把四周学习全部完成当作投递前置条件。

W2 请求治理与支付轮询

对应简历: 请求能力、TanStack Query、账号状态、订单结算、支付 Flow;公共请求层也是候选补充经历。

A:请求治理案例,25 分钟

推荐讲述骨架:

三端分别维护请求逻辑时,传输错误、业务反馈和账号清理容易耦合。我把公共业务依赖收敛到平台无关 Request Client,三个 App 分别创建 Transport 并注入 Header、地址及上传差异。请求层统一响应解析与错误分类,Flow 和页面决定如何反馈,required 401 由根会话边界处理。

对读取请求,Query 提供 AbortSignal,并只对可恢复错误有限重试;Mutation 不自动重试。这样规则有明确归属,也能针对响应协议、并发 401、取消和重试分别验证。

错误分类:business、unauthorized、network、timeout、cancelled、http、protocol、unknown。记住含义比背八个英文单词重要:业务拒绝不等于断网,合法 HTTP 响应不等于合法业务协议。

B:请求追问与账号边界,25 分钟

面试追问 回答要点与边界
为什么 Request 不能直接弹 Toast? 它不知道是首屏读取、后台刷新还是用户提交;首屏可显示错误态,后台可保留旧内容,动作失败由 Flow 决定反馈
并发 401 怎么处理? 每 App 独立协调器,required 请求在同一登录会话中只通知一次,新会话 reset;public/optional-user 不直接触发同一清理逻辑
清缓存就解决账号切换了吗? 先取消旧读取,再清 Query/Mutation 缓存;端侧还要清草稿和身份信息,重建订阅。PC/M 整页导航,RN 根业务区域通过 key 重挂载
用户资料失败就是未登录? 不是。用户对象、明确游客 null、尚无数据以及请求失败需要区分,避免网络错误被当作游客
什么时候可以重试? 项目公共读取只对可恢复错误最多补发一次;业务错误、401、协议错误、取消等不重试,429 当前不固定短延迟重试
为什么支付失败不能直接重发? 超时不代表服务端没有执行。先查状态并按接口合同处理,幂等键和服务端约束需另行确认
AbortSignal 能撤销后端写入吗? 不能;它可让支持信号的客户端读取停止,但不能证明后端撤销了已收到的操作
日志为什么不直接打 error 全对象? 可能带 URL、参数、凭据和正文;项目只保留 operation、状态、业务码、requestId 等白名单信息

账号切换清 Mutation 缓存不等于取消已经提交的写请求;前端协调器也不是所有会话竞态的万能保证。测试范围和未完成可靠性治理需分开说明。

C:支付案例与轮询手写,40 分钟

先用五分钟理解业务: 购物车结算和立即购买有不同入口,预览身份用 orderType + previewKey 隔离;URL 定位,Zustand 保存未提交上下文,Query 保存服务端预览。支付跳转后还需查询结果、识别终态、刷新相关缓存。后端幂等是否实施必须按真实接口核实。

题目: 实现串行轮询,达到终态就返回;请求失败立即抛出;限制总次数;外部可取消,取消后不接收旧结果。以下为教学实现,不是公司源码。

type PollResult<T> = { done: boolean; data: T };

function wait(ms: number, signal: AbortSignal): Promise<void> {
  return new Promise((resolve, reject) => {
    if (signal.aborted) return reject(signal.reason);
    const onAbort = () => {
      clearTimeout(timer);
      signal.removeEventListener('abort', onAbort);
      reject(signal.reason);
    };
    const timer = setTimeout(() => {
      signal.removeEventListener('abort', onAbort);
      resolve();
    }, ms);
    signal.addEventListener('abort', onAbort, { once: true });
  });
}

async function poll<T>(
  query: (signal: AbortSignal) => Promise<PollResult<T>>,
  signal: AbortSignal,
  maxAttempts = 20,
  intervalMs = 1500,
): Promise<T> {
  if (!Number.isInteger(maxAttempts) || maxAttempts < 1) {
    throw new RangeError('次数必须是正整数');
  }
  if (!Number.isFinite(intervalMs) || intervalMs < 0) {
    throw new RangeError('间隔必须是非负有限数');
  }
  for (let count = 0; count < maxAttempts; count++) {
    signal.throwIfAborted();
    const result = await query(signal);
    signal.throwIfAborted();
    if (result.done) return result.data;
    if (count + 1 < maxAttempts) await wait(intervalMs, signal);
  }
  throw new Error('达到查询上限,结果仍未确认');
}

// 调用方创建 AbortController,将 signal 传入;离开页面时 abort()。

这个实现用 await + setTimeout 等上次结束后再等待,不会像固定间隔启动任务那样重叠。传输层必须消费信号才能真正停止请求;如果 query 忽略信号且一直不结束,外层也不能及时结束,需由实际请求实现超时/取消。次数上限不是总耗时上限。

达到上限只是“结果未确认”,不能告诉用户“支付失败”;请求错误也应交给调用方区分。生产读取重试是另外一层受限策略,不能在 catch 中无条件一直轮询。

自查场景: 第一次就终态;连续未完成恰好调用 N 次;第二次请求失败;等待期间取消;请求期间取消后旧结果返回。40 分钟内优先写主循环,来不及可解释等待函数的清理逻辑。

D:投递与反馈,30 分钟

选择 2~3 个匹配岗位,记录这一版简历的主案例。没有匹配项就继续筛选,不为数量把所有方向都投一遍。

W3 购物车与 React

对应简历: 核心交易流程、Query/Zustand、业务 Flow、测试与状态边界。

A:把购物车画成状态表,25 分钟

状态 主要归属 为什么
商品、库存、服务端金额 Query 需要回源与缓存一致性
选中商品、编辑目标、提交阶段 Flow 的本地状态与组合 Hook 属于当前页面交互,跟随有效列表校准
跨页结算草稿 端侧 workflow Store 在页面间保留未完成流程,账号切换时清理
输入框暂存值、键盘和弹窗布局 端侧 UI 平台输入体验不同,不能覆盖服务端准源

推荐讲述:

购物车最容易出问题的是一次操作包含多个异步阶段。修改数量后,界面不能在写请求返回时立即解锁,还要等待服务端重新给出库存、数量和金额。项目把修改放在 Query Mutation,成功和失败后都回源;Flow 统一选择、备注、删除确认和结算导航,端侧负责表现。

添加、删除与修改的刷新策略并不一样:添加和删除成功后刷新,修改数量或备注则成功失败都刷新。失败时保留必要编辑状态,列表变化后清理无效选择。这样每个阶段由谁处理是清楚的。

B:React 与状态追问,25 分钟

问题 参考回答
为什么修改失败还刷新? 库存拒绝可能伴随服务端校准,不能把本地输入继续当最终值;重新读取真实结果
回源失败就是写入失败吗? 不是。写入可能已成功,应区分写操作错误和列表刷新错误,避免误导再次提交
useState 可以做同步防重入锁吗? 不能直接保证。一次渲染闭包里仍是旧状态;本项目购物车使用提交状态限制 UI,不承诺同一轮渲染前的同步重复调用只执行一次
为什么认证可用 ref 锁? ref 可同步更新而不触发渲染,适合入口互斥;state 另用于展示。锁只保护该实例,仍不等于后端幂等
派生状态为什么不放 Effect? 能从数据和选择直接计算的金额、可用性,优先直接派生,避免额外渲染和两份状态失步
useMemo 保证数据正确吗? 不保证;它是计算缓存优化。正确性来自纯计算、完整依赖和明确数据来源
Effect 为什么读到旧值? 闭包捕获当次渲染。按语义补依赖、使用函数式更新,或为长生命周期回调保存最新 ref
key 在哪里重要? 同层节点身份;列表排序不宜用索引代表业务身份,聊天 ACK 前后要保持稳定 clientKey
怎么验证状态链? 用真实 Hook/QueryClient,控制确认、写入、回源、导航的 Promise,验证各阶段与失败恢复;UI 和 RN 真机另验证

C:模拟一轮,40 分钟

前 25 分钟按下列题序回答,后 15 分钟只记三个缺口:

  1. 2 分钟:自我介绍,说明自己的职责。
  2. 5 分钟:为什么抽公共业务,举一个不该抽的例子。
  3. 4 分钟:购物车修改失败后,界面怎么恢复。
  4. 4 分钟:账号切换时旧 Query、草稿、订阅分别怎么办。
  5. 8 分钟:从本文补充练习中写异步提交锁,说明不能保证什么。
  6. 2 分钟:问面试官一个关于团队或交付流程的问题。

这只是第一轮短模拟,并非真实面试时长预测。如果以 RN 为主,可用 W4 的 RN 项目卡替换第 2、3 题。

D:继续投递与查看进展,30 分钟

保留岗位记录,按实际消息处理沟通;投递 2~3 个匹配岗位作为建议量。遇到正式面试,替换本周模拟和投递时段,超出的时间如实记录。

W4 按岗项目卡与求职问答

第 4 周 A、B 两次各选一张项目卡或一个最明显缺口,C 再模拟一次,D 复盘投递。下面材料都在本页,但不要求本周全部复习。

岗位侧重 优先选择 补充
React / Next.js 架构、请求、SKU 或支付 购物车、后台、聊天
React Native / Expo RN 稳定性、EAS/OTA、深链 公共业务、请求和平台适配
后台与业务开发 运营后台、TMS、PDA 表格、扫码、上传与流程校验
核心开发或负责人 架构、交付、真实协作案例 AI 验证、任务拆分、线上问题;头衔需匹配实际职责

项目卡 1:SKU 规格联动

对应简历: 枚举有效属性组合、Path Map、库存和购买约束。

讲述草稿: 多规格商品不能等全部选完才提示无库存。我根据有库存 SKU 生成可达属性组合,用户选中某属性后,把其他候选与已选属性组合查询,动态禁用无效选项。全部选择后再匹配 SKU,并校验起购量与库存上限。

追问与要点:

  • 为什么用 Map?预处理组合,用查询换取每次交互时更简单的判断。
  • 换选“颜色”时怎么组合?去掉已选颜色,只与其他属性组合,否则把两个颜色同时作为条件会误判。
  • 有 S 个 SKU、K 个维度,复杂度怎样?枚举子集有指数项;每次排序生成 Key 可概括为 O(S × 2^K × K log K),适用于维度受限的业务。
  • Key 怎么避免冲突?属性 ID 与值 ID 成对规范化,不只拼显示名称;注意分隔符和重复值。
  • 库存变了怎么办?重建派生结果、校准当前选择,最终以下单接口校验为准。

小练习: 用“红/M 有库存、蓝/L 有库存、红/L 无库存”手画有效组合;选红后,L 应不可选;替换成蓝时不能仍带入红。然后阅读本文末尾 Path Map 练习。

项目卡 2:WebSocket 客服聊天

对应简历: 共享聊天 Flow、重连、会话隔离、ACK、去重和重发。

讲述草稿: 发送消息先本地回显,记录待确认状态;收到服务端确认后用稳定 clientKey 更新同一条消息,同时记录服务端 ID 去重。不同订单或运单用业务身份隔离,历史分页与实时消息合并。断线和 ACK 超时要转成可理解的失败状态,并清理旧监听与定时器。

追问与要点:

  • WebSocket 连接成功不等于业务消息已保存,ACK 才是另一层业务确认。
  • ACK 超时不等于服务端未收到;重发需要结合服务端幂等或状态查询,不能宣称 exactly-once。
  • TCP 的连接内有序不覆盖断线重连、历史分页合并和业务重复。
  • 稳定 React key 避免从临时 ID 换服务端 ID 时重建节点;去重规则另按服务端 ID/业务确认设计。
  • 重连延迟和指数退避可作为方案比较;是否已在项目采用,要按实现说明,不能把建议写成现状。

验证思路: 延迟 ACK、重复回包、切换业务会话、断线重连、历史页与实时消息重叠。讲一个自己实际排查过的场景。

项目卡 3:RN 稳定性

对应简历: Expo SDK 54→56、RN 0.81→0.85、NativeWind 2→4,iOS 启动与 Android Tab 崩溃。升级过程和修复结论来自既有简历/面试材料,本轮未重新查验崩溃日志。

iOS 案例讲述: 先判断崩溃发生在业务页面还是 Runtime 初始化;既有材料记载 Hermes Runtime 与 Bundle 编译配置不一致。讲清当时的日志线索、构建配置对比、如何统一版本、重新构建原生壳及复测;回忆不出的诊断环节列为待补证据,不编造排查过程。

Android 案例讲述: 既有材料记载 ViewPager2/RecyclerView 回收路径崩溃,最终将高风险标签页改为单内容实例与手势切换。取舍要讲清:减少原生多实例交互后,页面状态保留、懒加载和手势冲突如何处理。

追问与边界: OTA 可更新兼容 Runtime 的 JS/资源,不能替换不兼容原生壳;冷启动、后台返回和多次切换应分别验证。只能说处理了有证据的高风险路径,不说全部崩溃归零。

项目卡 4:深链与发布

对应简历: App Links、Universal Links、邀请归因、云效 CI/CD、EAS、双商店发布。

深链讲述: 已安装 App 时唤起目标页面,未安装时提供 H5/商店入口;来源参数和邀请码经过入口、登录、注册仍保持清晰归属。Android 关联应用签名与域名,iOS 关联应用身份与域名;登录回跳只接受允许的内部路径或来源,避免直接信任任意 URL。

交付讲述: Web 使用 standalone 制品、版本目录、current 软链接切换、PM2 重载和健康检查,失败时尝试回退。原子的是版本指针切换,不代表发布全过程零故障或数据库兼容自动解决。

追问与要点: EAS Build 构建安装产物,Submit 上传分发平台,Update 发布兼容的 JS/资源;Runtime 与更新通道需匹配。证书、签名、版本、审核问题只讲本人真实负责部分。准备一个实际失败或回退例子,说明如何确认恢复;不能把“有脚本”等同于已经演练成功。

项目卡 5:BBDbuy 运营后台

对应简历: Umi Max、Ant Design、仓储、条码、退款、客服、ECharts。

30 秒稿: 这是面向采购、仓库、财务、客服和运营的一体化平台。我参与从零搭建及持续迭代,重点负责的模块以实际职责补充。项目贯穿收货、验货、上架、拣货打包与出库;除了表格录入,还需要处理条码和作业顺序、退款审核、批量导出及作业看板。

追问与要点: Code 128 条码生成不等于业务状态合法,扫码后仍要校验对象与可执行动作;全局 WebSocket 连接和页面订阅要区分生命周期;退款批量处理应区分单项失败和整批失败;ECharts 组件卸载要释放实例,尺寸变化按实际布局处理。仓库单日作业数字描述平台场景,不是前端开发效率。

练习: 选一个自己负责的仓储页面,说明“扫错码、重复扫码、当前状态不可操作”时分别怎样反馈。

项目卡 6:BBD 仓库小助手 PDA

对应简历: Vue 3、uni-app、useScanner/useSubmit、上传、弱网、WGT。

30 秒稿: Android PDA 面向仓库一线,以包裹、商品和货位条码驱动作业。我负责范围以实际经历为准,重点讲扫码入口、提交互斥、图片视频留档与弱网反馈,说明连续操作时怎样避免重复触发和卡住。

追问与要点: 防抖只合并短时间输入,不等于异步互斥;提交锁要 finally 释放;并发上传需要限制任务数、跟踪进度并区分单项失败;上传重试不代表业务写入可无条件重试;WGT 更新前端资源,原生插件、权限或 SDK 变化仍需新安装包。

练习: 写本文的异步锁或并发池,用一个失败任务解释恢复方式。不要将简历中的“幂等重试”直接扩展为所有弱网操作都自动重试。

项目卡 7:新智慧 TMS

对应简历: React/Umi、MobX、Handsontable、合同与 PDF、国际化、PDA 容器联调。

30 秒稿: 我主要参与物流 TMS 的业务页面与公共能力建设,包括配置化表格、批量录入,以及 uni-app 容器中 H5 页面的联调。重点说明某一类重复录入或表格配置问题怎样改善,不把参与开发讲成独立设计整个系统。

追问与要点: createColumns 按列类型统一文本、日期、条码与操作配置;Handsontable 的粘贴、下拉和校验要与业务提交合同一致;容器承载 H5 复用快,但通信、跨域、Cookie、返回栈与硬件调用需联调。打印/PDF 要区分屏幕布局与分页效果,不能只看页面截图。

练习: 选一次真实联调,讲清自己处理到哪一层,哪些属于原生、后端或硬件团队。

项目卡 8:Manifest V3 浏览器扩展

对应简历: 采购平台订单/SKU 匹配、物流采集和批量回填。

30 秒稿: 第三方物流后台缺少接口,采购人员需要跨多个已登录页面查询和回填。我做的扩展利用 content script 与 tabs/scripting 操作目标页面,用 storage 保存任务映射,按订单、平台和规格匹配,只对成功匹配的结果回填并保留人工确认。

追问与要点: 选择扩展是为了在运营人员的现有浏览器会话中工作;DOM 改版时选择器可能失效,需要错误反馈和可恢复状态;权限、消息参数和操作范围要收紧。不要把前端 DOM 匹配说成后台权威数据校验。

练习: 描述一次“未匹配/多条匹配/页面失效”时如何停止错误回填。没有真实案例时标记待回忆,不编造节省人时。

求职与个人贡献问答

问题 可用的组织方式
为什么考虑换工作? 结合真实情况说明想进一步发展的方向和希望改善的工作条件;例如希望继续做 React/RN 复杂业务,也更重视可持续节奏。具体取舍由本人决定
期望薪资多少? 先填期望、最低接受值、税前税后与固定/浮动口径,再结合实际岗位表达;本文不代填数字
很多是 AI 写的,你做了什么? 如实说明借助 Codex;举一次自己定义问题、比较方案、发现错误、验证修复并承担交付的例子。不会解释的部分就承认还在补齐
作为负责人怎么协作? 用一个真实任务讲拆分、接口约定、Review、联调、发布分工;没有人员管理事实,不把技术协调变成绩效管理
最难的问题是什么? 选能讲清证据的一个:请求会话、购物车一致性或 RN 崩溃。包含失败尝试和最终取舍,不只复述成功方案
有哪些不足? 选一个真实且正在改进的缺口,说明行动与目前进展;不套用“过于追求完美”
工作空档怎么解释? 按真实时间和原因简洁说明,再回到当前准备与能力;不编造自由职业、外包或学习经历填空档

可反问:岗位入职前三个月最重要的任务是什么?团队如何分工与 Review?线上问题和发布由谁负责?实际工时、休息安排与招聘描述如何对应?挑两项与自己决定相关的即可。

基础速查:从简历进入原理

这部分用于追问时查漏,不单独增加每天的背诵任务。回答时先说原理,再用本页项目举例。

主题 应能说清的答案 简历入口
JavaScript 引用与拷贝 展开和 Object.assign 是浅拷贝;嵌套对象仍共享,不能原地修改 Query 缓存;深拷贝还需定义循环引用、特殊对象等边界 SKU、Query
事件循环 当前任务的同步代码结束后处理微任务;浏览器在渲染机会绘制,不保证每个任务后都绘制。定时器延迟不是准确执行时间 支付轮询
Promise.all 结果按输入顺序;任一失败外层拒绝,已启动的其他操作并不会自动取消 上传
闭包 回调保留创建时的作用域;React 每次渲染产生新的绑定,长期订阅容易读旧值 聊天、Effect
TypeScript 联合类型配合判别字段表达互斥状态;unknown 使用前收窄,any 绕过检查;类型在运行时擦除,接口仍需响应校验 RequestError、Flow
React 渲染 state、父组件、Context 或外部订阅可触发渲染;重新执行组件不等于 DOM 一定变化 购物车、后台
Effect 与布局 Effect 用于同步外部系统并清理资源;必须在绘制前测量时才考虑 layout effect,避免无谓阻塞绘制 ECharts、聊天
Query Key 包含决定结果的稳定参数;staleTime 管新鲜期,gcTime 管无订阅后的保留时间,不要混为一谈 预览身份、交易列表
缓存更新 invalidate 让数据失效并可触发回源;setQueryData 直接改缓存;乐观更新还要处理取消旧读取、回滚和并发冲突 购物车
Zustand 适合跨页草稿和本地流程上下文;不能因方便就再存一份全部服务端实体 结算草稿
Next.js 页面边界 结合项目说明服务端读取/渲染与客户端交互的职责;浏览器能力不能在服务端直接使用。用了 Next 不等于所有页面都做 SSR/SEO PC、H5
页面渲染与 CSS 区分 Layout、Paint、Composite;频繁读写布局可能迫使同步计算。Flex/Grid 解决布局,长文本需要明确换行与溢出策略 多端 UI、看板
CORS、XSS、CSRF CORS 是浏览器跨源读取授权;XSS 是不可信内容执行;CSRF 利用自动携带的身份凭证诱导请求,三者问题不同 H5、WebView
ESM/CJS ESM 可静态分析且导出为 live binding;CommonJS 运行时加载。Tree Shaking 还取决于副作用、导出和构建配置 Monorepo
幽灵依赖与循环依赖 使用未声明依赖可能在某台机器偶然可用;循环依赖可能读到未初始化或未完成导出 公共包拆分
国际化 公共业务文案按领域组织,端侧负责展示框架;检查缺失 key、插值、日期/金额和长文案布局,不只翻译按钮 七语言三端
测试分层 纯计算验证规则;Hook/Query 验证生命周期;Web E2E 验证页面;RN 原生仍需对应设备验证 质量与交付

五分钟基础自测: Promise 回调和定时器谁先执行?为什么 React 状态不直接原地改?TS 类型能否保证接口返回合法?staleTime 和 gcTime 有何区别?取消请求为什么不能证明支付没发生?每题先独立说两句,再看表。

补充手写练习

全部是面试教学代码,采用现代 JavaScript/TypeScript 运行环境,未用于替换项目实现。一次选一题:先确认输入输出,独立写,再对照参考与边界。W2 轮询和 W3 提交锁为主线,其余按实际岗位追问选择。

练习 1:异步提交锁

简历入口: PDA 连续扫码、认证提交。题目要求任务执行期间拒绝新的提交,成功失败都释放锁。

function createSubmitLock() {
  let pending = false;
  return async function run<T>(task: () => Promise<T>): Promise<T> {
    if (pending) throw new Error('处理中');
    pending = true;
    try {
      return await task();
    } finally {
      pending = false;
    }
  };
}

检查: 首次成功、首次失败后再提交、处理中第二次调用、同步抛错。解释为什么必须 return await 后再 finally 释放;不能提前返回未完成的 Promise 就把锁释放。这只保护一个实例,多个标签页、重启、多设备仍需服务端规则。

练习 2:带取消的防抖

简历入口: 输入、扫码或查询触发。约定尾沿执行,连续调用只保留最后一次参数与 this。

function debounce<A extends unknown[], C>(
  fn: (this: C, ...args: A) => void,
  delay: number,
) {
  let timer: ReturnType<typeof setTimeout> | undefined;
  const wrapped = function (this: C, ...args: A) {
    clearTimeout(timer);
    timer = setTimeout(() => {
      timer = undefined;
      fn.apply(this, args);
    }, delay);
  };
  wrapped.cancel = () => {
    clearTimeout(timer);
    timer = undefined;
  };
  return wrapped;
}

检查: 连续触发、最后参数、保留 this、取消后不执行。追问节流时,先说明它限制触发频率,首沿/尾沿是合同选择;防抖和节流都不能代替异步提交锁。

练习 3:有限并发上传池

简历入口: PDA 图片/视频上传。约定保持结果顺序,同时执行不超过 limit;一个任务失败时外层拒绝。

async function mapLimit<T, R>(
  items: T[],
  limit: number,
  worker: (item: T, index: number) => Promise<R>,
): Promise<R[]> {
  if (!Number.isInteger(limit) || limit <= 0) {
    throw new RangeError('limit 必须是正整数');
  }
  const results = new Array<R>(items.length);
  let next = 0;
  async function consume() {
    while (next < items.length) {
      const index = next++;
      results[index] = await worker(items[index], index);
    }
  }
  await Promise.all(
    Array.from({ length: Math.min(limit, items.length) }, consume),
  );
  return results;
}

检查: 空列表、limit 无效、完成顺序不同、单项失败。复杂度除任务本身外为 O(N),结果空间 O(N)。本简化版外层拒绝后,其他 worker 可能继续领取和执行任务;要 fail-stop、收集所有结果或取消在途请求,都需要显式扩展合同。

练习 4:明确边界的有限重试

简历入口: 公共请求与 Query。调用方必须传 shouldRetry,避免所有错误默认重试。下面复用 W2 的可取消 wait。

async function retryRead<T>(
  task: (signal: AbortSignal) => Promise<T>,
  shouldRetry: (error: unknown) => boolean,
  signal: AbortSignal,
  retries = 1,
): Promise<T> {
  if (!Number.isInteger(retries) || retries < 0) {
    throw new RangeError('重试次数必须是非负整数');
  }
  for (let attempt = 0; ; attempt++) {
    signal.throwIfAborted();
    try {
      const result = await task(signal);
      signal.throwIfAborted();
      return result;
    } catch (error) {
      signal.throwIfAborted();
      if (attempt >= retries || !shouldRetry(error)) throw error;
      await wait(Math.min(500 * 2 ** attempt, 2000), signal);
    }
  }
}

检查: 不可重试错误只调用一次;retries=1 最多两次总调用;等待时取消;重试成功。本题表达机制,不替代项目的 Query 策略;429、重试抖动、每次请求超时和业务幂等需要按合同另处理,不用于自动重发支付。

练习 5:数组版 Promise.all

简历入口: 多文件任务与批量请求。约定接收数组,保留输入顺序,允许普通值。

function allArray<T>(items: Array<T | PromiseLike<T>>): Promise<T[]> {
  return new Promise((resolve, reject) => {
    if (!items.length) return resolve([]);
    const values = new Array<T>(items.length);
    let remaining = items.length;
    for (const [index, item] of items.entries()) {
      Promise.resolve(item).then((value) => {
        values[index] = value;
        if (--remaining === 0) resolve(values);
      }, reject);
    }
  });
}

检查: 空数组、普通值、乱序完成、失败、稀疏数组。forEach 会跳过空位,因此此处使用 entries 遍历;这是数组简化题,不是完整 iterable 泛型或原生 Polyfill。失败不取消其他任务。

练习 6:SKU 组合可达性

简历入口: Path Map。题目简化为判断组合是否存在,不维护 SKU ID、价格或全部选项 UI;每条 SKU 的规格必须是一组属性 ID / 值 ID。

type Spec = readonly [propertyId: string, valueId: string];
type SkuInput = { stock: number; specs: Spec[] };

const pathKey = (specs: Spec[]) => JSON.stringify(
  [...specs].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0),
);

function buildPaths(skus: SkuInput[]) {
  const paths = new Set<string>();
  for (const sku of skus) {
    if (sku.stock <= 0) continue;
    const ids = sku.specs.map(([id]) => id);
    if (new Set(ids).size !== ids.length) {
      throw new Error('同一 SKU 的属性 ID 必须唯一');
    }
    let subsets: Spec[][] = [[]];
    for (const spec of sku.specs) {
      subsets = subsets.concat(subsets.map((part) => [...part, spec]));
    }
    for (const part of subsets) {
      if (part.length) paths.add(pathKey(part));
    }
  }
  return paths;
}

检查: 零库存忽略、无效组合、同名不同属性、属性顺序变化。JSON 编码减少字符串分隔符歧义;这个生成方式避免位运算 32 位限制,但仍有指数级组合开销,只适合业务约束下的小维度。候选查询时先移除同属性旧选择,再加入候选。

练习 7:聊天订阅与去重口述题

若面试追问 EventEmitter,先写 Map<事件名, Set<监听器>>:on 返回取消订阅函数;off 移除监听器;emit 对监听集合快照逐个调用;once 包装回调并在执行前取消。再说明回调异常是否影响其他监听器,这是需定义的合同。

消息去重则用另一张映射,按业务会话和稳定消息 ID 合并历史与实时消息。不能把 EventEmitter 的监听器去重当成消息去重;ACK 的临时消息匹配和失败重发仍是业务规则。

所有题目的收尾: 用 20 秒说明它对应哪段简历、还缺什么生产保护、哪些责任属于服务端。深拷贝、LRU、call/new/instanceof 等如果在真实反馈中反复出现,再纳入下一轮,不把所有题同时加到四周任务里。

投递、模拟与复盘

每次练习的方式

25 分钟表达练习可分为:5 分钟独立回答、10 分钟对照本文、5 分钟重讲、5 分钟记卡点。遇到个人事实或代码细节不确定时,再回查原始证据;日常练习不需要来回切换几份说明文档。

模拟面试不看参考答案,结束后按三项各记 0~2 分:业务与个人职责是否清楚、方案与取舍是否解释清楚、验证与边界是否准确。分数用于比较自己的两次练习,不预测录用结果。

可把下面这段直接交给 AI 开始模拟:

请基于这份文档对我做一次前端面试。一次只问一题,先等我回答,不提前提供答案。优先围绕 BBDbuy 架构、请求、购物车及我选择的项目卡追问个人职责、取舍和证据;穿插一题基础或手写题。不将参考答案当成我已经掌握的技能。最后指出最需要改的三个问题,并区分事实待核实、理解缺口和表达问题。

面试前 15 分钟检查

用时 检查内容
3 分钟 岗位要求、投递的简历版本、时间线口径
5 分钟 自我介绍与今天主讲的两个案例
4 分钟 最容易卡住的两道追问,不新学整章
3 分钟 面试时间、方式、设备或路线,以及两个反问

求职条件先留空,由自己决定

条件 我的期望 不接受的情况
React / Next.js / RN 方向 ________ ________
薪资及税前税后、固定与浮动口径 ________ ________
双休、下班时间、加班情况 ________ ________
城市与通勤范围 ________ ________
职责范围、团队支持与发布责任 ________ ________

时间线优先核对:现有简历写 2021.04 开始工作、2024.04 入职包包达;个人档案记为 2022 年开始工作、2025.04 开始第三份工作。实际实习、转正与中间经历尚未统一,这份计划不替你判定哪组正确。

投递与面试记录表

一份岗位一行。状态按实际填写,例如待投、已投、沟通中、已约面试、面试后待反馈、结束;不要预填结果。

日期 / 公司 / 岗位 匹配点与主要缺口 状态 / 简历版本 下一步与日期
________ ________ ________ ________
________ ________ ________ ________
________ ________ ________ ________
________ ________ ________ ________

面试后尽量在当天用 10 分钟记录:问了什么、哪题卡住、需要补什么、下一步何时进行。优先保留真实问题,不扩展成新的整套题库。

忙起来如何缩减

  • 正常周:120 分钟。 按四个时段执行。
  • 忙碌周:30 分钟。 10 分钟讲一个项目问题、10 分钟处理一个岗位或面试进展、10 分钟记录下一步;其余顺延。
  • 没有精力的一周:可以暂停。 不补欠账,不把下一周加倍。正式面试准备优先替换其他练习。

连续两周没有回复时,先检查岗位匹配、简历开头与投递渠道;样本少时不直接下结论。如果有面试但项目追问答不清,就优先练项目;如果重复卡在同一类基础题,就定向补这一类。

四周结束后,按“做了什么、实际耗时、收到了什么反馈、下一轮改变什么”复盘。只根据真实记录调整,不预设面试数或 offer 数。

保存与使用

这份 Markdown 是计划原稿,可在资料库打开并打印,勾选格和空白用于手写。文档中的方框不是自动保存的网页进度;如要记录电子进度,直接编辑本文件中的完成情况。

资料依据:个人档案中的单休、晚下班与年度跳槽意向;「最新简历(2026-09)」「面试准备总览」「简历项目讲述与追问」「从简历扩展的前端基础与手写题」;2026-09-11 对 BBDbuy 本地代码的阅读。本文已将日常练习需要的经历与答案融入,不要求先阅读其他文档。原简历是已提供版本的记录,本文是可调整的学习与执行材料。

整合时对参考材料中的边界做了明确区分:前端提交限制不等于后端幂等,源码存在不等于已完成线上验证,轮询达到次数上限不等于支付失败。本文 7 个 TypeScript 示例通过类型检查及代表性行为检查,但仍是教学示例,不代表生产实现或完整验收。任务顺序、用时和投递数量均为建议,不是新的个人事实。

自序 · 个人档案 2026-09-11