跳到主要内容

小程序面经

核心考点

1. 双线程架构

  • 渲染层(WebView):负责 WXML/WXSS 渲染,每个页面一个 WebView
  • 逻辑层(JS Engine / V8):执行业务逻辑,独立线程,无法直接操作 DOM
  • 通信:通过 JSBridge 与 Native 通信,数据经序列化传递
  • 优点:安全(逻辑层无法直接操作 UI);缺点:通信有延迟,setData 数据量大性能差

2. 生命周期

App: onLaunch → onShow → onHide → onError
Page: onLoad → onShow → onReady → onHide → onUnload
  • onLoad:只执行一次,接收页面参数
  • onReady:页面初次渲染完成
  • onShow / onHide:前后台切换时触发

3. 性能优化

  • setData 优化:只传变化的数据,避免大对象;使用路径更新 'list[0].name'
  • 列表渲染wx:key 必须设置,避免重复渲染
  • 图片懒加载lazy-load 属性
  • 分包加载:主包 < 2MB,总包 < 20MB,按需加载分包
  • 骨架屏:提升首屏体验

4. 与 H5 / App 的区别

对比小程序H5App
运行环境微信/支付宝等宿主浏览器原生系统
发布需审核随时需审核
能力受宿主限制受浏览器限制几乎无限制
体验接近原生较差最好

5. 跨端框架对比

框架原理优缺点
Taro编译时转换React 语法,生态好,编译有差异
uni-app运行时 + 编译Vue 语法,覆盖平台多
mpx增强编译贴近原生写法,性能好

6. 高频面试题

  • 小程序登录流程:wx.login 获取 code → 后端换取 openid + session_key → 返回自定义 token
  • WXS 是什么:在渲染层运行的脚本,可减少逻辑层通信,提升性能
  • 自定义组件通信:父→子 properties;子→父 triggerEvent;兄弟通过父或 EventBus
  • 为什么不能用 window/document:逻辑层没有 DOM/BOM 环境
  • 微信支付流程:后端下单 → 返回支付参数 → 前端 wx.requestPayment → 回调处理

微信小程序实战面经

实战高频考点

1. 登录与鉴权完整流程

前端 wx.login() → 获取 code

发送 code 到自己的后端

后端调用微信接口:code2Session
→ 返回 openid + session_key + unionid

后端生成自定义 token,存 Redis

前端存 token 到 storage,后续请求携带

常见问题

  • session_key 有有效期,需定期调用 checkSession 验证
  • wx.getUserInfo 已废弃,用 wx.getUserProfile(需用户触发)
  • unionid 需满足:已关联公众号/小程序,或绑定开放平台

2. 支付流程

1. 前端发起支付请求到自己后端
2. 后端调用微信统一下单接口 → 返回 prepay_id
3. 后端用 prepay_id 签名生成支付参数
4. 前端调用 wx.requestPayment({ timeStamp, nonceStr, package, signType, paySign })
5. 用户支付完成 → 微信回调后端 → 后端更新订单状态
6. 前端 success 回调只做提示,不以此为支付成功依据(以后端通知为准)

3. 自定义组件高级用法

behaviors(类似 mixins)

const loginBehavior = Behavior({
data: { isLogin: false },
methods: {
checkLogin() { /* ... */ }
},
lifetimes: { attached() { this.checkLogin() } }
})

Component({
behaviors: [loginBehavior],
// 自动拥有 loginBehavior 的数据和方法
})

抽象节点(类似 slot 的高阶用法)

{ "componentGenerics": { "selectable": { "default": "./default-item" } } }

4. 小程序云开发

  • 云函数:Node.js 环境,免鉴权调用微信 API,自动获取 openid
  • 云数据库:文档型数据库,支持实时监听
  • 云存储:文件上传下载,wx.cloud.uploadFile
  • 云调用:云函数中调用微信开放能力(发送订阅消息等)
// 云函数端
exports.main = async (event, context) => {
const { openid } = context.OPENID // 自动获取,无需手动传
return db.collection('users').where({ _openid: openid }).get()
}

5. 分包策略详解

{
"subpackages": [
{ "root": "packageA", "pages": ["pages/cat", "pages/dog"] },
{ "root": "packageB", "pages": ["pages/apple"] }
],
"preloadRule": {
"pages/index": { "network": "all", "packages": ["packageA"] }
}
}
  • 独立分包:可不依赖主包运行(分享页、广告页)
  • 分包预加载:用户在某页面时提前加载指定分包

6. 调试与发布

  • vconsole:小程序内置调试面板,wx.setEnableDebug({ enableDebug: true })
  • 抓包:Charles/Whistle 配合代理,需在微信开发者工具开启
  • 体验版/预览版:真机测试不经过审核
  • 灰度发布:后台配置按比例放量

7. 高频面试题

  • 小程序如何做埋点? 封装统一 Page/Component,重写 onShow/tap 等生命周期
  • 如何实现全局错误监控? App.onError + wx.onError 捕获未处理异常
  • 小程序能访问 cookie 吗? 不能,用 wx.setStorageSync 替代
  • 如何做长连接? wx.connectSocket WebSocket API
  • 页面间传参的方式? URL 参数、globalData、EventBus、本地存储

跨端框架深度对比(Taro / uni-app / Flutter)

跨端技术选型

1. Taro 深入

技术架构

开发语言:React / Vue
|
Taro 编译器
/ | \
微信 支付宝 H5 RN
小程序 小程序 Web 原生应用

Taro 3.x 运行时架构(重要变化)

  • 老版本:编译时转换,将 JSX 转成小程序模板语言
  • Taro 3.x:运行时适配,小程序运行 React/Vue 全量,通过运行时模拟 DOM API
  • 优点:支持 React 全部特性;缺点:包体积大、性能差一些

Taro 特性

// 内置组件:跨端封装
const App = () => (
<View className="container"> {/* 转为 div / wx:view */}
<Text>Hello</Text> {/* 转为 span / wx:text */}
<Image src={img} /> {/* 转为 img / wx:image */}
<ScrollView scrollY> {/* 转为 各平台滚动组件 */}
{list.map(item => (
<View key={item.id}>{item.name}</View>
))}
</ScrollView>
</View>
)

// 平台判断
import Taro from '@tarojs/taro'
if (Taro.getEnv() === Taro.ENV_TYPE.WEAPP) {
// 微信小程序独有逻辑
}

性能优化

  • 采用 @tarojs/plugin-html 可直接使用 HTML 标签
  • 长列表用 VirtualList 组件
  • 采用分包加载减小主包体积

2. uni-app 深入

技术架构

开发语言:Vue 3
|
uni-app 编译器
/ | | \
微信 支付宝 H5 App
| |
各家小程序 iOS/Android
<!-- 页面组件 -->
<template>
<view class="container">
<!-- 条件编译:不同平台显示不同内容 -->
<!-- #ifdef MP-WEIXIN -->
<text>微信小程序独有内容</text>
<!-- #endif -->
<!-- #ifdef H5 -->
<text>H5独有内容</text>
<!-- #endif -->
<text>所有平台共有</text>
</view>
</template>

uni-app 的 App 端

  • H5+(HTML5 Plus)运行时:WebView 内嵌小程序逻辑 + 原生渲染
  • nvue:基于 Weex 的原生渲染,性能较好
  • uts(TypeScript 超集):编写原生插件,能调用原生 API

3. Flutter

核心架构

Dart 代码
|
Flutter 引擎
/ \
IOS Android
原生 原生
实现 实现

Flutter vs 小程序跨端

  • Flutter 不依赖小程序容器,更适合面向 App 开发
  • 小程序跨端(Taro/uni-app)主要面向微信、支付宝等平台
  • Flutter 性能更接近原生,小程序跨端更快上手

4. 三种方案综合对比

对比项Taro 3.xuni-appFlutter
开发语言React/VueVueDart
跨小程序5家+10家+不支持
跨原生 AppRNWeex完整支持
性能
包体积较大
社区活跃活跃活跃
适用场景前端团队小程序为主App 为主

5. 常见坏呓与解决

Taro 常见问题

1. 样式差异:小程序不支持部分 CSS 选择器,用 Taro 内置样式集或注意兼容性
2. 事件处理差异:小程序事件对象属性与 H5 不同,用内置组件
3. 包体积过大:按需加载、分包加载
4. Redux/Zustand 在微信小程序端需配置特殊适配

uni-app 常见问题

1. 条件编译容易遗忘:/* #ifdef MP-WEIXIN */ 由编译器处理
2. nvue 与 Vue 的样式差异: nvue 采用 Flex 布局,不支持所有 CSS
3. App 端原生能力需要通过 uts 或和 Native 插件实现

6. 资深面试题

  • Taro 3.x 的运行时适配分导是什么思路?
    • 小程序没有真实 DOM,运行时实现了一套虚拟 DOM API
    • React/Vue 操作虚拟 DOM, Taro 将虚拟 DOM 映射为 setData 调用
    • 比编译时转换灵活,但性能有损耗
  • 如何选择跨端框架?
    • 已有 React 团队且面向小程序 -> Taro
    • 已有 Vue 团队且小程序为主 -> uni-app
    • 面向 iOS/Android App,小程序不是主要 -> Flutter
    • 需要高性能原生 App -> 纯原生开发
  • 跨端框架如何处理平台差异?
    • 条件编译(Taro: process.env.TARO_ENV,uni-app: #ifdef)
    • 抓象平台能力到中间层,应用层不写平台相关代码

小程序性能深度优化实战

小程序性能优化深度

1. setData 性能优化

为什么 setData 影响性能?

  • 逃逸层线程不能直接操作 DOM
  • setData 数据经过序列化 -> Native 通信 -> 渲染层更新
  • 数据量大、调用频繁就会成为瓶颈

优化实践

// 1. 只传必要的字段
const { list, count } = this.data
// bad
this.setData({ list: newList }) // 传辘1000条数据
// good
this.setData({ 'list[5].status': 'done' }) // 只传变化的字段

// 2. 减少 setData 次数(批量合并)
// bad
this.setData({ count: 1 })
this.setData({ loading: false })
// good
this.setData({ count: 1, loading: false })

// 3. 防抖高频调用(scroll 事件)
let timer
onScroll(e) {
clearTimeout(timer)
timer = setTimeout(() => {
this.setData({ scrollTop: e.detail.scrollTop })
}, 100)
}

// 4. 分屏渲染(分批设置大列表)
async function renderBatch(list) {
const BATCH = 20
for (let i = 0; i < list.length; i += BATCH) {
this.setData({ [`list`]: list.slice(0, i + BATCH) })
await new Promise(r => setTimeout(r, 16)) // 一帧的时间
}
}

2. 页面渲染优化

骨架屏

<!-- 骨架屏:首屏删叨剩留作平衡 -->
<view wx:if="{{loaded}}">
<real-content />
</view>
<view wx:else class="skeleton">
<view class="skeleton-avatar" />
<view class="skeleton-line" />
<view class="skeleton-line short" />
</view>

图片懒加载

<!-- 小程序内置支持 -->
<image lazy-load="{{true}}" src="{{item.url}}" />

<!-- 街道模式:Intersection Observer -->
// IntersectionObserver 实现懒加载
Page({
onReady() {
const observer = this.createIntersectionObserver()
observer.relativeToViewport({ bottom: 100 })
observer.observe('.load-more', (res) => {
if (res.intersectionRatio > 0) {
this.loadMore()
}
})
}
})

3. 分包策略深度

主包优化策略

{
"pages": [
"pages/index/index",
"pages/home/home"
],
"subpackages": [
{
"root": "packageUser",
"name": "user",
"pages": ["pages/profile", "pages/settings"]
},
{
"root": "packageOrder",
"name": "order",
"pages": ["pages/list", "pages/detail"]
}
],
"preloadRule": {
"pages/index/index": {
"network": "wifi",
"packages": ["user"]
}
}
}

分包最佳实践

  • 主包只放起始页和公用组件、工具库
  • 按功能模块划分分包
  • preloadRule 配置分包预加载
  • 独立分包用于分享页、广告部置

4. 内存与渲染性能

内存优化

// 1. 图片内存管理——避免重复创建
const imageCache = new Map()
function getImage(url) {
if (!imageCache.has(url)) {
imageCache.set(url, wx.createImage ? wx.createImage() : null)
}
return imageCache.get(url)
}

// 2. 组件销毁时清理引用
Component({
lifetimes: {
detached() {
this._timer && clearInterval(this._timer)
this._observer && this._observer.disconnect()
}
}
})

// 3. 大数据分页加载,不要一次性读取全量
Page({
data: { list: [], page: 1, hasMore: true },
async loadMore() {
if (!this.data.hasMore) return
const res = await api.getList({ page: this.data.page })
this.setData({
list: [...this.data.list, ...res.data],
page: this.data.page + 1,
hasMore: res.hasMore
})
}
})

5. 小程序性能分析工具

1. 微信开发者工具 Audits 面板
- 体验评分:启动性能、页面渲染、用户体验
- 结合常见优化建se建议

2. Timeline / Performance 面板
- 录制页面操作过程
- 分析帧率、Script 耗时、Rendering 耗时

3. 真机调试
- 阴影模式测试(模拟低配置设备)
- 强制缓慢网络测试

6. 资深面试题

  • 小程序首屏渲染优化思路?
    • 减少主包体积,提卸加载到分包
    • 首屏数据在 onLoad 中请求并打开下一页齐平行发起
    • 马鼓属屏 + 骨架屏 + 首屏内容尽早请求
    • 首屏外的图片延迟加载
  • setData 渲染 1000 条数据如何优化?
    • 虚拟列表组件(只渲染可视区域)
    • 分屏渲染,每帧只 setData 一小批
    • 尸体数据尽量小,只存 key 字段而非全量对象
  • 小程序页面切换数据如何保存?
    • 小程序没有路由層缓存,页面切换后重新创建
    • 解决:app.globalData / Storage / 页面层参数传递
    • Taro/uni-app 可配置页面缓存 (keepAlive)