跳到主要内容

谈谈小程序相关原理

谈谈小程序底层原理​

  • 通过微信客户端提供的运行环境,将逻辑层和渲染层分离,运行在不同进程中

  • 每次初始化的时候,都会创建webview来展示页面,每个页面都是一个新的webview,保证每个页面都有独立的渲染环境,多个webview层叠 【提供了很好的用户体验和安全性(相互独立)】

  • 页面会有多个webview, position -> z-index值不同,小程序页面使用多个webview层叠实现的页面加载

  • 小程序的视图是在 WebView 里渲染的,webview底层还是 HTML (原生 HTML 太开放了,直接采用 HTML 作为渲染层语言,会有一些安全问题。因此,微信设计一套组件框架——Exparser。基于这个框架,内置了一套组件,以涵盖小程序的基础功能)

    • 一些自定义组件,比如text组件,底层就是span,view组件,底层就是div

谈谈小程序双线程模型​

多个渲染层和一个逻辑层

1、小程序的渲染层和逻辑层分别由2个线程管理:渲染层的界面使用了WebView 进行渲染;逻辑层采用JsCore线程运行JS脚本

2、一个小程序存在多个界面,所以渲染层存在多个WebView线程,而这些线程之间的通信会通过微信客户端进行中转。逻辑层发送的网络请求也会通过Native层进行转发

  • 小程序是双线程,第一个是渲染线程【ui渲染】,第二个是逻辑线程【执行js逻辑计算】
  • 小程序的双线程模型并不是用的web worker,而是单独起了一个运行js的沙箱线程。如果使用web worker,那么worker子线程与js主线程是在同一个 web page(或webview)运行时内的,会受到浏览器分配给每个web page的性能约束。而小程序渲染线程由webview承担,js线程是跟webview无关的、独立的线程,所以性能上比web worker好很多
  • 逻辑与渲染分离的线程分工模式一方面能够保证运行在逻辑线程沙箱内的 JavaScript 代码是线程安全的,另一方面由于渲染线程保证了对用户交互行为的快速响应,提高了用户体验。

渲染层和逻辑层在同一个进程吗​

逻辑层和渲染层并不在同一个进程中。微信小程序的运行环境采用了多进程架构,其中逻辑层和渲染层分别运行在不同的进程中

  • 逻辑层运行在一个独立的 JSCore 进程中
    • 负责处理小程序的逻辑、数据交互和业务处理等。它主要运行 JavaScript 代码,管理小程序的数据和状态,并且可以进行网络请求、数据计算和逻辑处理等操作
  • 渲染层运行在另一个独立的 WebKit 进程中,负责渲染小程序的界面展示。渲染层通过解析 WXML(微信小程序的界面描述语言)和 WXSS(微信小程序的样式描述语言),将界面元素绘制在屏幕上

多个webview页面如何去共享一个App变量?​

微信小程序会把所有的js文件都放在了一个线程,即JsCore线程

  • 因为js都在一个线程里,所以js文件都能共同访问app.js文件里变量

多个webview会造成什么问题?​

多个webview渲染层,会造成内存占用问题

  • 所以避免占用内存过大,小程序页面栈有限制,不超过10层

页面栈超过10层会将最后一层替换掉

谈谈小程序内存管理​

  • 观察内存情况
    • 开发者可以使用「模拟器」中的「Performance」或「JavaScript Profiler」面板,分析小程序逻辑层的 JS 执行情况
  • 优化内存
    • setData方法优化
      • 局部更新(颗粒度更新),而不是整体更新。这样可以减少不必要的内存占用
    • 及时释放不需要的资源,如定时器、事件监听

谈谈小程序登录流程​

appid: 每个小程序对应一个唯一的id

openid:微信号(用户)在某个应用程序中的唯一 ID

code:临时凭证

  • 方式一:手机号授权流程

    • 通过button的getPhoneNumber 的接口 来进行手机号授权
    • 用户允许授权之后,获取code临时凭证
    • code凭证传给后端,后端调用微信提供的api
    • 后台就返回对应的手机号,完成登录
  • 方式二:调用wx.login获取code临时凭证

    • code传递给后端,后端通过接口去微信后端换取到openid和 sessionKey
      • openId:登录成功后用户的唯一id
      • session_key: 对用户数据进行加密签名的密钥
    • 后端拿到openid和 sessionKey进行相关逻辑处理 (用户验证等)、生成token

谈谈小程序分包​

为什么要分包​

随着业务量加大,小程序包的体积可能越来越大

  • 小程序要求压缩包的体积不能大于2M, 否则无法发布
  • 实际开发中小程序体积如果大于2M就需要使用分包机制
  • 分包后可解决2M的限制,并且能分包加载内容,提高性能
  • 用户在使用时才按需加载分包,即可以优化小程序的首次启动的时间

注意:

  • 整个小程序所有分包大小不超过16M 【所有包大小不超过16M】
  • 单个分包/主包大小不能超过2M 【每个包的大小不超过2M】

分包如何划分​

  • 按照业务逻辑划分
  • 除tabBar之外的页面全部做成分包
    • 这样既解决了启动的问题, 也可以避免主包过大的问题. 具体如何划分分包、可依据项目实际情况去选择

谈谈小程序性能优化​

  • 小程序首屏加载优化
  • 小程序包体积优化
  • setData优化
  • 图片优化
  • 内存优化
  • 使用worker
  • 主包优化

小程序首屏加载优化​

  • 合并请求:
    • 首页请求了较多的接口,可以考虑合并请求
  • 分逻辑调用接口:
    • 部分接口可以分逻辑调用,可以根据具体场景进行逻辑判断,并非所有场景下都需要调用接口
  • 资源预加载:
    • 预加载首页所需的静态资源,如图片、样式等,可以提前加载这些资源,减少页面加载时的等待时间,提升用户体验
  • 按需加载、延迟加载:
    • 比如首屏渲染的时候,图片加载会占有一定的时间,可以将图片通过滚动加载、只加载可视区域部分,而不是一次性加载

小程序包体积优化​

  • 针对wxss样式,可以自己实现一个脚本,把无用的样式给去掉,小程序不同与h5,小程序对包体积要求比较极致,既然样式没有使用到,就不应该存在代码中

  • 组件分包异步化加载

    • 对于较大的组件库或功能模块,可以考虑将其打包为独立的分包,并在需要时异步加载
  • 尽可能少兼容老版本浏览器

    • 在package.json,可以调整browserlist的配置,调整之后,可以减少大量无用的css兼容语法
  • 主包优化

主包优化问题​

如果主包体积已经快接近2M, 并且分包也快到了20M, 这时候如何优化?

  • 1、可以将小程序的一些主包的页面,某些组件页面,通过H5来内嵌,这样可以减少包的体积

  • 2、分析第三方库的依赖来分析包的体积,提取公共模块,减少包体积

  • 3、css代码优化

    • 合并重复的样式
    • css压缩
  • 4、页面的逻辑代码,有相同逻辑的,可以提取出来放在公共代码里面

主包有哪些内容?

  • 主包:一般只包含项目的启动页面或TbbBar页面

    • tabbar页面必须是主包
    • 一些分包需要用到的公共资源(样式、js、图片)可以放在主包
      • 因为分包可以使用主包的东西

setData优化​

  • setData不能一次性传太多数据,如果列表太长,可以分开渲染
  • setData调用过于频繁
  • 跟页面无关的数据不要保存在data中,不要用setData更新,因为setData会触发页面渲染
  • setData支持颗粒更新,可以指定到具体的属性值更新

为什么setData不能传太多数据​

由setData的底层实现可知,当数据量过大的时候,会增加脚本和编译执行时间,占用webview渲染线程和JsCore逻辑线程

为什么setData不能频繁调用​

在我们分析过的⼀些案例里,部分小程序会非常频繁(毫秒级)的去setData,其导致了两个后果: Android 下⽤户在滑动时会感觉到卡顿,操作反馈延迟严重,因为 JS 线程⼀直在编译执行渲染,未能 及时将用户操作事件传递到逻辑层,逻辑层亦无法及时将操作处理结果及时传递到视图层; 渲染有出 现延时,由于 WebView 的 JS 线程⼀直处于忙碌状态,逻辑层到页面层的通信耗时上升,视图层收到 的数据消息时距离发出时间已经过去了⼏百毫秒,渲染的结果并不实时;

简单来说,每次setData都要经过逻辑层和渲染层,逻辑层和渲染层是不同进程。频繁调用每次经过2个进程会影响性能和用户体验

图片优化​

  • 可以使用CDN+OSS
  • 雪碧图
  • svg
  • 懒加载

内存优化​

  • 通过内存分析,可以使用「模拟器」中的「Performance」或「JavaScript Profiler」面板,分析小程序逻辑层的 JS 执行情况

  • 分析内存分布情况,排查内存泄漏问题

  • 合理使用分包加载

    • 使用分包加载可以优化加载启动的耗时,也可以减低内存的占用
  • 控制 WXML 节点数量和层级

    • 一个太大的 WXML 节点树会增加内存的使用
    • 对于长列表来说,使用虚拟列表,控制当前展示的节点数量

使用worker​

  • 对于复杂计算、耗时计算可以利用Worker线程来处理
  • Worker是一个独立的线程,它运行在后台,并且与主线程(渲染线程)分开,这样可以避免主线程被阻塞,从而提高小程序的响应速度和性能。

使用步骤

在 app.json定义workers字段来存放workers的目录,如果是uniapp/taro在manifest.json

  • 1、创建Worker实例
  • 2、向Worker发送消息
  • 3、Worker计算完数据之后,将结果发送给主线程
  • 4、主线程监听Worker返回的消息

发送消息通过postMessage,监听消息通过onMessage

小程序worker使用限制

  • Workers 之间不支持发送消息

谈谈小程序嵌入h5​

text
<web-view :src="url"></web-view>
  • 通过web-view组件嵌入h5

  • 在小程序管理后台成功配置业务域名后,才可使用web-view组件

  • 如果主包非常接近2m,而且也做了分包,但是主包体积还是很大,可以考虑可以将一些主包的页面,某些组件页面,通过H5来内嵌,这样可以减少主包的体积

嵌入h5的页面加载很慢,如何解决?​

  • 优化h5的首屏页面加载
  • h5体积过大,加载下载文件,会增加加载时间问题
  • 检查小程序和h5

嵌入h5出现白屏问题?​

  • 检查业务域名是否有配置
    • 登录小程序后台(微信公众平台),添加业务域名 (开发管理->开发设置->业务域名)
  • 域名只支持https协议,检查h5域名协议

小程序和h5通信​

  • 通过url参数
    • 缺点:url 数据量有限
  • postMessage
    • 使用小程序SDK
    • wx.miniProgram.postMessage

谈谈小程序缓存​

  • 缓存存储大小:同一个微信用户,同一个小程序 storage 上限为 10MB
  • 缓存存储隔离:每个微信用户来说,存储是隔离的,a用户无法读取b用户的数据
  • 图片缓存:小程序可以缓存已经加载过的图片

谈谈小程序上传和下载​

  • wx.chooseMedia、wx.chooseVideo、wx.chooseImage

    • 让用户选择图片或视频文件
  • wx.uploadFile 将选择的文件上传到服务器

    • 需要提供上传的URL以及文件的路径
  • wx.downloadFile 下载文件资源到本地

注意事项:

  • 文件大小限制:小程序对上传文件的大小有限制,默认最大上传限制为50MB