HuaJun Interview Notes

2/9/2026 interview

# 上海华君智能科技有限公司

# 一、工作经历介绍

我的第一段经历是在 [公司A],负责 智能会议室解决方案 的全栈开发。这是一个典型的设备接入与实时管控项目。通过 MQTT/WebSocket 协议与会议室中的各种硬件(如灯光、投影、门禁)进行通信,实现了设备状态的实时监控与集中操控。

随后,在 [公司B]OTA(汽车远程升级)平台 项目中,我的工作重心从设备管控转向了海量数据处理与高可靠交互。我负责使用 Vue 3 + TypeScript + Vite 重构并维护升级包管理模块的核心流程,包括升级包的上传、差分、校验、任务下发与进度跟踪。

最近一段经历是在 [公司C],我参与开发了一个基于 ElectronPCB电路板故障检测 的桌面端应用。这让我接触到了工业级视觉检测场景。我负责缺陷复判工作台的前端开发,需要将 AI 算法筛选出的海量疑似缺陷图片(通常一个批次上万张)进行高效、清晰的展示,并提供给质检员便捷的交互操作(如放大、旋转、标注、分类)。

# 二、大量数据页面的前端界面设计

# 后端优化

  • 分页 + 筛选 + 排序 + 增加数据库索引

# 前端优化

  • 接口防抖 (debounce)
  • 对复杂状态进行缓存 (computed)
  • 异步组件 + 组件懒加载:
    import { defineAsyncComponent } from 'vue'
    const AsyncComp = defineAsyncComponent(() => import('./components/MyComponent.vue'))
    
  • 虚拟列表(管理已渲染的 DOM 元素)
  • <Teleport>
  • 依赖按需导入(Tree-Shaking)

# Vite 生产构建优化

// vite.config.js - 生产配置
export default defineConfig({
  build: {
    minify: 'terser', // 代码压缩
    terserOptions: {
      compress: {
        drop_console: true, // 移除 console
        drop_debugger: true
      }
    },
    reportCompressedSize: true, // 显示压缩后大小
    chunkSizeWarningLimit: 1000 // chunk 大小警告阈值 (KB)
  }
})

# 三、Composition API VS Options API

  1. 允许通过 逻辑功能组织代码(解决 Options API 中 datamethodwatch 等分离的痛点)
  2. 逻辑复用,可以封装成 Hook 像导入函数一样使用(Options API 使用 Mixins)
  3. 和 TypeScript 支持好,Composition API 基于普通的变量和函数,可以直接配合 TypeScript 可以获得更好的类型提示。

# 四、Vue 3 中实时数据连接的设计与实现

  • WebSocket:适合双向、高频、低延迟的交互场景,如设备实时控制、多端状态同步。
  • SSE:适合服务器向客户端单向推送的场景,如告警通知、数据日志流,实现更简单,自带断线重连。
  • 全局单例模式,用状态管理库(如 Pinia)来集中管理连接和数据:
<script setup>
import { useRealtimeStore } from '@/stores/realtime'

const realtimeStore = useRealtimeStore()
// 在应用启动时连接
onMounted(() => {
  realtimeStore.connect('wss://iot-platform.example.com/ws')
})
</script>
<!-- DeviceMonitor.vue -->
<script setup>
import { useRealtimeStore } from '@/stores/realtime'
import { computed } from 'vue'

const props = defineProps<{ deviceId: string }>()
const realtimeStore = useRealtimeStore()

// 通过计算属性获取特定设备数据,自动响应更新
const currentDeviceData = computed(() => {
  return realtimeStore.deviceData.get(props.deviceId)
})

// 发送控制指令
const handleControl = () => {
  realtimeStore.sendCommand({
    deviceId: props.deviceId,
    command: 'reboot'
  })
}
</script>

# 五、前端测试策略设计

# 三层测试策略

# 1. 单元测试(Unit Testing)

  • 测试目标:纯函数、工具函数、业务逻辑钩子
  • 技术选型:Vitest + @vue/test-utils
  • 优势:速度快,反馈及时,确保最小代码单元行为正确
// 测试一个数据转换函数
import { parseSensorData } from '@/utils/sensorParser'

describe('parseSensorData', () => {
  it('应正确解析温度传感器数据', () => {
    const raw = { deviceId: 'temp-01', value: 25.3, unit: 'C' }
    const result = parseSensorData(raw)
    expect(result.displayValue).toBe('25.3°C')
    expect(result.isWarning).toBe(false)
  })
})

# 2. 组件测试(Component Testing)

  • 测试目标:Vue组件的渲染、交互和状态
  • 适用场景
    • UI组件:按钮、输入框、模态框等基础组件
    • 业务组件:设备卡片、实时数据图表、报警列表
    • 异步逻辑:API调用或WebSocket数据更新响应
  • 关键技术:Vitest + @vue/test-utils + Mock外部依赖
import { mount } from '@vue/test-utils'
import DeviceCard from '@/components/DeviceCard.vue'
import { useDeviceStore } from '@/stores/device'

// 模拟Pinia Store
vi.mock('@/stores/device')

describe('DeviceCard.vue', () => {
  it('点击控制按钮应调用Store的对应方法', async () => {
    const mockControl = vi.fn()
    useDeviceStore.mockReturnValue({ sendControlCommand: mockControl })
    
    const wrapper = mount(DeviceCard, {
      props: { device: { id: '1', name: 'Test Device', status: 'online' } }
    })
    
    await wrapper.find('.control-btn').trigger('click')
    expect(mockControl).toHaveBeenCalledWith('1', 'toggle')
  })
})

# 3. 端到端测试(E2E Testing)

  • 测试目标:完整的用户流程和业务场景
  • 适用场景
    • 关键业务流程:登录 → 设备选择 → 数据查看 → 控制指令
    • 跨页面跳转和复杂交互
    • 与WebSocket实时数据、地图集成等功能
  • 技术选型:Cypress 或 Playwright
  • 特点:编写成本高但信心度最高,用于核心业务流程验证

# 六、困难的问题及解决方法

生产环境下 Mongodb数据库写入了但读取不到

  • 查询了数据库的部署架构和应用的连接配置。发现问题核心在于:我们的MongoDB部署了主从复制集(一主二从),但应用的读写配置是分离的——写入操作指向主库(Primary),而读操作默认指向了从库(Secondary)。由于网络传输和副本应用需要时间,主从之间存在复制延迟。在写入后的极短时间内查询从库,数据尚未同步过去,导致“读不到”。

  • 我采用了 writeConcern 策略来确保写操作的一致性级别。我修改了写入数据时的代码,在关键的创建、状态更新操作中,设置了 { w: “majority” }。这意味着写入操作必须等待数据被复制到“大多数”(超过一半)的节点(包括主库和至少一个从库)并确认后,才向客户端返回成功。