





小程序和普通网页最大的不同,是它跑在一个双线程模型里:一个线程负责渲染界面(视图层),另一个线程负责跑业务逻辑(逻辑层)。两个线程并行工作,通过消息通道传递数据。理解这套机制,才能明白为什么小程序比网页流畅、为什么setData要少传数据。
普通网页里,JavaScript逻辑和页面渲染共用一个WebView线程。JS算数据的时候,页面就卡住不能动;页面在渲染的时候,JS也得等着。复杂页面同时跑动画和数据请求时,很容易出现掉帧和卡顿。用户感觉页面"不跟手",根源就在单线程互相阻塞。
小程序面向的是高频使用场景,用户对滑动流畅度要求很高。如果逻辑和渲染挤在一个线程里,复杂列表页滑动时一定会卡。微信团队设计双线程模型,就是为了把这两件事拆开,各跑各的,互不堵。
视图层运行在专门的渲染环境里,使用类似WebView的技术;逻辑层运行在类似JSCore的环境里,没有DOM操作能力。两层之间不能直接读写对方的变量,只能通过官方提供的接口发消息。这种隔离让逻辑层的JS计算不会阻塞渲染,视图层的滚动和动画也不会因为业务逻辑复杂而掉帧。
隔离还带来安全性。小程序里的第三方代码跑在逻辑层,拿不到视图层的DOM对象,也就不能随意篡改页面结构。这比网页里JS直接操作DOM要可控得多,也是小程序能被企业用来做交易工具的技术基础。
视图层接收逻辑层传过来的数据,把WXML模板和数据拼成真实界面,再把用户的点击、滑动事件转发给逻辑层。开发者写的页面结构和样式最终都在视图层执行。视图层不做业务判断,它只负责"数据长什么样就画成什么样"。
视图层还负责处理渲染层面的细节:组件的默认样式、布局计算、滚动惯性。大田县这类用户量大的城市,线上机型碎片严重,视图层要适配从老旧安卓机到最新iPhone的各种屏幕尺寸。开发者写的一份WXML,最终在不同机型上呈现效果由视图层自动对齐,开发者不用为每种机型单独写代码。
逻辑层是小程序的大脑:处理用户点击事件、请求后端接口、计算页面数据、管理页面状态。开发者写的JS代码全部跑在这里。逻辑层算好最新数据后,通过setData发给视图层,视图层再更新界面。逻辑层不直接改页面长什么样,它只提供数据。

视图层和逻辑层之间有一个系统级消息通道。逻辑层调用setData把数据发过去,视图层收到后重新渲染对应区域;用户在视图层点击按钮,视图层把事件对象通过同一个通道发回逻辑层触发事件处理函数。所有跨线程通信都是序列化后传输的,不能直接传函数或引用。
因为要经过序列化和线程切换,每一次setData都有固定开销。数据量小的时候感觉不到,一次传几百个列表项或者频繁setData,通道就会成为瓶颈。这也是为什么官方建议只传视图层需要的字段,不要把整个对象都发过去。
setData是小程序开发中最容易被误用的接口。有些开发者把整个用户信息对象每次都setData一遍,哪怕只改了一个昵称。正确做法是只传变化的字段,比如this.setData({'user.nickname': '新名字'}),而不是把整个user对象重新发一遍。
频繁触发setData也会拖慢界面。比如输入框每次按键都setData一次,快速打字时通道被堵满,输入就会延迟。这种场景应该做防抖处理,停止输入几百毫秒后再统一setData一次。理解双线程通信成本,写出的小程序才能真正流畅。
页面卸载时也要注意清理。逻辑层在页面关闭后如果还在跑定时器或者监听事件,会继续占用消息通道,导致后续页面操作变慢。正规做法是在页面的un生命周期里把定时器清掉、把全局监听解绑。这些细节单看不明显,但累积起来就是老小程序越用越卡的原因之一。
理解双线程模型后,开发者写代码时就会自然注意哪些数据该放逻辑层缓存、哪些必须走setData。这不是性能优化技巧,而是小程序前后端开发基础原理的核心思维方式。