从前端到后端:一个大专生的技术野路子成长记

林浩天★
2026-01-04 02:37
阅读 570

去年夏天,我揣着大专毕业证和一堆自学笔记,硬是靠刷了200多道 LeetCode 和几个 GitHub 项目,混进了杭州一家做 SaaS 的创业公司。岗位是前端开发,月薪 8K,MacBook Pro 是入职一周后自己咬牙买的——别笑,Windows 跑 Chrome DevTools 卡得像 PPT,调试个 flex 布局都能让我原地升天。

现在工作快一年了,最近在偷偷准备跳槽,白天写业务代码,晚上刷题+看源码。但说实话,真正让我成长的,不是那些八股文,而是一次“被迫跨界”的实战经历。今天就想聊聊那次既踩坑又涨姿势的技术探索。


事情得从上个月说起。我们团队负责一个客户管理后台,前端用 Vue3 + TypeScript,后端是 Node.js + Koa。本来前后端各司其职,井水不犯河水。直到产品经理老张在周会上扔出一句话:“我们要支持自定义字段导出 Excel,下周上线。”

我当场就懵了。导出 Excel?不就是点个按钮,后端吐个 CSV 或 xlsx 文件吗?结果后端小哥直接摆手:“现在接口只返回 JSON,Excel 导出逻辑太重,前端搞吧。”

我???

前端搞 Excel 导出?行吧,毕竟我司信奉“能前端做的绝不麻烦后端”(其实是后端人手不够)。于是,我火速调研了 xlsx 库,三下五除二写了个导出功能。本地测试没问题,结果上线第二天,客服炸了——有个客户导出 5000 条数据,浏览器直接卡死,Chrome 标签页白屏,用户以为系统崩了。

那一刻我真的想砸电脑。但冷静下来一想:问题不在工具,而在架构。把重型数据处理放在前端,本身就是反模式。尤其当数据量不可控时,纯前端方案就是定时炸弹。


后端介入,才是正解

我鼓起勇气找后端小哥聊:“能不能把 Excel 生成放到服务端?前端只传字段配置,后端拼数据、生成文件、返回下载链接。”
他皱眉:“你确定?这得改接口,还得加队列,怕影响主流程。”
我说:“总比让用户等三分钟然后白屏强吧?”

最后技术老大拍板:做!但有个前提——不能阻塞主线程,必须异步处理

于是,我们开始了一次小而美的前后端协作实践。

第一步:前端只负责“告诉后端要什么”

我重构了前端逻辑,不再拉全量数据,而是只传:

  • 需要导出的字段列表(比如 ['name', 'email', 'custom_field_1']
  • 查询条件(分页、筛选等)
  • 用户 ID(用于权限校验)
// 前端发起导出请求
const exportConfig = {
  fields: selectedFields,
  filters: currentFilters,
  userId: currentUser.id
};

await axios.post('/api/export/excel', exportConfig);
// 返回 { taskId: 'task_123' }

这样,前端从“数据搬运工”变成了“指令发送者”,轻量又安全。

第二步:后端异步生成,状态轮询

后端收到请求后,不立即处理,而是:

  1. 创建一个导出任务,存入 Redis(带过期时间)
  2. 推入 RabbitMQ 队列(其实我们用的是 Bull,基于 Redis 的队列)
  3. 立即返回 taskId 给前端

前端拿到 taskId 后,开始轮询任务状态:

let retryCount = 0;
const checkStatus = async () => {
  const { status, downloadUrl } = await axios.get(`/api/export/status/${taskId}`);
  
  if (status === 'completed') {
    window.open(downloadUrl); // 触发下载
  } else if (status === 'failed') {
    showErrorMessage('导出失败,请重试');
  } else if (retryCount < 30) {
    retryCount++;
    setTimeout(checkStatus, 2000); // 每2秒查一次
  }
};

这套机制虽然简单,但解决了两个核心问题:

  • 不阻塞:用户点击后立刻有响应,不会卡住界面
  • 可追踪:失败了也能知道原因,而不是静默崩溃

第三步:后端生成 Excel 的性能优化

最开始,后端直接用 xlsx 库读数据库、拼数据、写文件。测试发现,5000 行数据要 8 秒。不行!

我们做了三点优化:

  1. 流式写入:不用一次性加载所有数据到内存,而是用 stream 逐行写入
  2. 数据库分页查询:每次只查 1000 条,避免 OOM
  3. 临时文件缓存:生成完的文件存 CDN,带 1 小时过期,避免重复生成

关键代码片段(Node.js + xlsx):

const XLSX = require('xlsx');
const fs = require('fs');

async function generateExcel(taskId, config) {
  const workbook = XLSX.utils.book_new();
  const worksheet = [];
  
  // 添加表头
  worksheet.push(config.fields.map(f => f.label));
  
  let offset = 0;
  const limit = 1000;
  let hasMore = true;

  while (hasMore) {
    const records = await db.query(`
      SELECT ${config.fields.map(f => f.key).join(',')}
      FROM users
      WHERE user_id = ?
      LIMIT ? OFFSET ?
    `, [config.userId, limit, offset]);

    if (records.length === 0) {
      hasMore = false;
    } else {
      // 转换为 Excel 行
      records.forEach(rec => {
        worksheet.push(config.fields.map(f => rec[f.key] || ''));
      });
      offset += limit;
    }
  }

  // 写入工作表
  XLSX.utils.book_append_sheet(workbook, XLSX.utils.aoa_to_sheet(worksheet), 'Data');
  
  // 流式写入文件(避免大内存占用)
  const filePath = `/tmp/export_${taskId}.xlsx`;
  XLSX.writeFile(workbook, filePath, { compression: true });
  
  // 上传到 CDN 并返回 URL
  const cdnUrl = await uploadToCDN(filePath);
  return cdnUrl;
}

优化后,5000 行数据生成时间从 8s 降到 2.3s,内存占用下降 60%。


技术选型背后的权衡

有人可能会问:为什么不用 CSV?更轻量啊。

确实,CSV 更快更省资源。但我们产品面向的是企业 HR,他们习惯用 Excel 打开文件,还经常要格式(比如日期、数字对齐)。CSV 打开后全是文本,体验差。所以技术决策不能只看性能,还得看用户场景

另外,为什么不直接用后端语言原生生成 Excel(比如 Java 的 POI)?因为我们是 Node.js 技术栈,团队熟悉 JS 生态,引入新语言成本太高。小团队,稳定压倒一切


这次实践带来的思考

这次“被迫”接触后端逻辑,让我意识到一个残酷现实:纯前端开发者,在复杂业务面前会越来越被动

以前我觉得“前端就是 UI + 交互”,但现在发现,真正的工程能力,体现在对整个链路的理解。比如:

  • 知道什么时候该让后端介入
  • 理解异步任务、队列、缓存这些后端概念
  • 能和后端同学用同一种语言讨论问题(不是吵架)

上周五晚上加班联调这个功能时,后端小哥突然说:“你这前端思维挺后端啊。” 我笑笑,心里却有点酸——这哪是天赋,分明是被业务逼出来的。


给同样背景朋友的一点建议

作为非科班、大专出身的开发者,我深知资源和机会的珍贵。如果你也像我一样:

  • 自学成才
  • 在小公司打杂
  • 想跳槽但怕被学历卡

我的经验是:不要把自己局限在“前端”标签里

你可以:

  • 主动了解后端接口设计(RESTful、GraphQL)
  • 学点基础运维知识(Docker、Nginx)
  • 甚至尝试写简单的 CLI 工具或脚本

不是为了转岗,而是为了拥有系统视角。当你能站在全栈角度思考问题,你的价值就不再是“切页面的人”,而是“解决问题的人”。


效果与后续

新导出功能上线两周,0 故障,平均生成时间 1.8s(1000 行以内),用户反馈“终于不卡了”。技术老大还在周会上夸我们“跨团队协作典范”(虽然我知道他只是想省招聘后端的钱)。

更重要的是,我开始主动参与需求评审,会问:“这个功能的数据量级是多少?是否需要分页/懒加载/服务端渲染?” 产品经理看我的眼神都变了——从“那个写样式的”变成“能一起想方案的”。


最后:技术探索的本质

回过头看,这次实践没什么高深算法,也没用上微服务、Serverless 这些 buzzword。它就是一个普通业务问题下的务实解法

但正是这些“脏活累活”,构成了我们日常工作的大部分。而所谓“技术成长”,往往就藏在:

  • 一次线上事故的复盘
  • 一段被重构的烂代码
  • 一场和后端同事的深夜对线

我不再幻想“写出改变世界的框架”,只希望下次遇到类似问题时,能更快找到平衡点——在用户体验、开发效率、系统稳定性之间。

毕竟,我们不是在写 demo,而是在造一艘能载着用户穿越风浪的船。


P.S. 如果你也在准备跳槽,别光刷算法。试着复盘你做过的每一个功能:有没有更好的架构?有没有可以抽象的模块?有没有和后端协作的优化空间?这些思考,面试时说出来,比背一百遍“虚拟 DOM 原理”都有用。

共勉。

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝