小程序底层架构剖析

news2024/11/25 16:28:52
c72661aaf19bce1038c2773eaf2559f9.jpeg

当我们前端切图崽网上冲浪的时候,会发现有很多技术文章都在分析vue框架,react框架,显少有分析小程序框架的。那今天就通过这篇短小精悍的文章带大家了解一下微信小程序的底层架构。(如无特殊说明,下文中提到的小程序都是微信小程序)

小程序的由来

我们先抛出一个问题,在没有小程序的时候,企业们都在微信里怎么运营? 答案就是小程序的“前身”-公众号,企业们普遍会把H5网站放在公众号作为流量转换的入口。但是h5确实让公众号遇到了一些问题。

首先就是白屏过程,对于一些复杂页面,受限于设备性能和网络速度,白屏会更加明显;再就是缺少操作反馈,比如页面切换生硬以及点击所带来的迟滞感等等;

微信团队内部通过JS-SDK以及后来的增强JS-SDK已经能够解决一些问题,但是对于上述问题是JS-SDK所处理不了的,急需一个全新的系统来完成,它需要具备以下能力:

  • 快速加载

  • 更强大的能力

  • 原生的体验

  • 易用且安全的微信数据开放

  • 高效,简单的开发

于是,小程序诞生了。

双线程架构

此处点题一下,本文我们讨论的是小程序的底层架构,其实,双线程架构就是小程序的核心。caaf5349ba817c3fcc1f401992716aa1.png那为什么要设计成双线程架构呢?首先我们来回顾一下浏览器的线程模型,浏览器是一个单线程架构,主要原因是js允许访问操作DOM,因此js线程和渲染线程只能互斥运行。

那小程序又是如何做到双线程的呢,根本原因就是微信小程序禁止js操作DOM。

使用双线程架构的优势一目了然:

  • 提高用户体验(ui和逻辑分离,避免页面长时间阻塞和卡顿)

  • 优化应用性能(运行在不同的线程中,可以同时渲染或者计算)

  • 开发效率更高(解耦和松散耦合)

接下来就带大家了解一下渲染层以及逻辑层的设计思路。

设计思路-渲染层

标签实现

小程序使用的是Exparser组件模型,Exparser组件模型与Web Components中的shadow DOM高度相似,微信为什么使用自定义组件框架,而不使用Web Components呢?主要还是出于安全考虑,并且方便管控。既然Exparser组件框架与shadow DOM高度相似,那么我们首先来了解一下shadow DOM。

shadow DOM: Web Components的一个重要属性是封装-可以将标记结构、样式和行为隐藏起来,并与页面上的其他代码相隔离,保证不同的部分不会混在一起,可使代码更加干净、整洁。其中,shadow DOM接口是关键所在,它可以将一个隐藏的,独立的DOM附加到一个元素上。

de6c134892e00378b71df5e5c5200c78.png

shadow DOM允许将隐藏的DOM树附加到常规的DOM树中-它以shadow root节点为起始根节点,在根节点的下方,可以是任意元素,和普通的DOM一样。

以上解释来源于MDN,其实shadow DOM并不神秘,像我们非常熟悉的video标签本质上就是用shadow DOM实现的。我们先打开chrome浏览器设置中的“打开用户代理shadow DOM”,然后再点击video标签就能看到。

91cc7dcdea3e343313343e8021c0f4b8.png

创建shadow DOM也非常简单,直接使用attachShadow方法就可以创建。

var shadow = Element.attachShadow({ mode: 'closed'})

Exparser组件模型:Exparser组件模型参考了shadow DOM并进行了一些修改,像事件系统就是完全复刻的,slot插槽,属性传递等都基本一致。但同时它又具有一些特点:

  • 基于shadow DOM模型:模型上与Web Components的shadow DOM高度相似,但不依赖浏览器的原生支持,也没有其他依赖库;实现时,还针对性地增加了其他API以支持小程序组件编程;

  • 可在纯JS环境中运行:这意味着逻辑层也具有一定的组件树组织能力;

  • 高效轻量:性能表现好,在组件实例极多的环境下表现尤其优异,同时代码尺寸也较小;

WXML编译

了解了小程序的组件系统之后,接下来看看WXML的编译过程。小程序中的DOM编译流程与vue类似,也会先将代码字符串编译为虚拟DOM,小程序中的虚拟DOM结构如下:WXML最终会被编译为JS文件,然后插入到渲染层的script标签中。

40c32436c2c0f7a583141980f4c1ab7d.png

2ef04037864bdcca82adee2651a264a1.png


WXSS动态适配

WXSS是小程序中使用的样式语言,WXSS具有CSS的大部分特性,同时它对CSS进行了扩充以及修改。

小程序中使用的尺寸单位为rpx(Responsive px),不同于h5中对于px的处理,需要使用postcss进行统一的转换,小程序底层已经为开发者做好了这层转换,那具体它是怎么做到的呢?

23474785e32d8e6561adf46dae8b21a7.png我们看它的这段源码,其实它与阿里的flexible.js方案是类似的,不同的是它做了一个精度收拢的优化,主要是为了解决1px的问题。

WXSS同样会经过编译,最终的编译产物为wxss.js,不同于WXML通过script标签的形式插入到渲染层,wxss.js则是通过eval的方式注入到渲染层代码中。

渲染层webview

全局变量: 渲染线程中存在着以下全局变量。

  • webviewId:webview的唯一标识,当用户打开一个小程序页面的时候,相当于打开了一个webview,不同的webview用webviewid来区分;

  • wxAppCode:整个页面的json wxss wxml编译之后都存储在这里;

  • Vd_version_info:版本信息;

  • ./dev/wxconfig.js:小程序默认总配置项,包括用户自定义与系统默认的整合结果。在控制台输入__wxConfig可以看出打印结果;

  • ./dev/devtoolsconfig.js:小程序开发者配置,包括navigationBarHeight,标题栏的高度,状态栏高度,等等,控制台输入__devtoolsConfig可以看到其对应的信息;

  • ./dev/deviceinfo.js:设备信息,包含尺寸/像素点pixelRatio;

  • ./dev/jsdebug.js:debug工具;

  • ./dev/WAWebview.js:渲染层底层基础库;

  • ./dev/hls.js:优秀的视频流处理工具;

  • ./dev/WARemoteDebug.js:底层基础库调试工具;

那小程序是如何快速启动一个webview的呢?

我们在打开pages/index/index视图页面时,发现DOM中多加载了一个__pageframe__/pageframe.html的视图层。这个视图层的作用正是小程序提前为一个新的页面层准备的。小程序每个视图层页面内容都是通过pageframe.html模板来生成的,包括小程序启动的首页。

下面来看看小程序为快速打开小程序页面做的技术优化:

  • 首页启动时,即第一次通过pageframe.html生成内容后,后台服务会缓存pageframe.html模板首次生成的html内容;

  • 非首次新打开页面时,页面请求的pageframe.html内容直接走后台缓存;

  • 非首次新打开页面时,pageframe.html页面引入的外链js资源走本地缓存; 这样在后续新打开页面时,都会走缓存的pageframe的内容,避免重复生成,快速打开一个新页面。

视图层打开新页面的流程

在创建每个视图层页面的webview时,都会为其绑定了onLoadCommit事件(它会在页面加载完成后触发,包含当前文档的导航和副框架的文档加载)。初始时webview的src会被指定为空页面地址http://127.0.0.1:${global.proxyPort}/aboutblank?${c},其中c为对应webview的id。webview从空页面到具体页面视图的过程如下:

  1. 空页面地址webview加载完毕后执行事件中的reload方法,即设置webview的src为pageframe地址;

  2. 加载完成后,设置其src为pageframe.html, 新的src内容加载完成后再次触发onLoadCommit事件但根据条件不会执行reload方法;

  3. pageframe.html页面在dom ready之后触发注入并执行具体页面相关的代码,此时通过history.pushState方法修改webview的src但是webview并不会发送页面请求;

设计思路-逻辑层

接下来我们看看小程序在逻辑层都做了哪些事情。

逻辑层与视图层通信

在小程序中,逻辑层只有一个,但是渲染层有多个,渲染层和逻辑层之间是通过微信客户端进行桥接通信的。那具体是怎么实现的呢?其实它使用的就是WeixinJSBridge通信机制。

在小程序执行的过程中,微信客户端分别向渲染层和逻辑层注入WeixinJSBridge,WeixinJSBridge主要提供了以下几个方法:

  • invoke:调用native API;

  • invokeCallbackHandler:Native 传递 invoke 方法回调结果;

  • publish:渲染层用来向逻辑业务层发送消息,也就是说要调用逻辑层的事件方法;

  • subscribe:订阅逻辑层消息;

  • subscribeHandler:视图层和逻辑层消息订阅转发;

  • setCustomPublishHandler:自定义消息转发;

渲染层如何向逻辑层通信?

95e842f778a55d8ad9ca8e739748aedc.png

89a86387cecc2cc0bde936f6914996a2.jpeg

渲染层向逻辑层通信的方式就是采用事件系统,以上就是完整的事件系统流程。

开发者在DOM上通过@click绑定事件,WXML文件被编译的时候,会通过$gwx函数生成虚拟DOM,然后小程序执行的时候渲染层底层基础库会对虚拟DOM进行解析,事件绑定最终会以attr属性的形式生成到虚拟DOM中,所以底层基础库通过applyPropeties解析事件并通过addEventListener绑定到相应DOM并声明回调。

用户点击相应DOM时,Exparser组件系统接收到这个事件,然后开始执行回调。回调函数在逻辑层,事件的触发在渲染层,此时,小程序会通过setData发送数据到逻辑层,这个时候WeixinJSBridge就派上用场了,渲染层调用publish方法发送数据,逻辑层通过registercallback进行监听,并执行相应的回调。此时,渲染层到逻辑层的通信流程结束。

逻辑层又是如何将改变后的数据回传给渲染层的呢?逻辑层改变数据之后,同样是触发setData方法,然后渲染层通过subscribe进行监听,从eventname和触发事件时候记录的回调函数来判断是哪个事件被触发了,从而获取动态数据。

第三方小程序框架

WXML,WXSS都是小程序的原生开发语言,使用原生语言开发还是存在诸多限制,尤其是17年小程序刚推出那会。因此,第三方小程序框架应运而生。第三方框架可以分为三大类。

第一类是预编译框架,预编译框架就是在执行前就进行编译。像我司在17年开发“转转二手交易网”的时候使用的wepy框架就属于预编译框架。预编译框架也有一些显而易见的缺点,这类预编译框架要么是类vue,要么是类React,如果后期vue或者React再出一些新特性的话,预编译框架就要进行扩展编写;还有一些兼容问题,对于小程序本身不支持的一些属性,预编译框架需要进行兼容;

第二类是半编译半运行框架,像美团的mpvue就是此类框架,半编译指的是vue的template需要单独编译为wxml,半运行讲的是vue整体的特性都会在逻辑层中运行。为了符合小程序的渲染框架,修改了vue的框架;

第三类是运行时框架,像Remax就是运行时框架,它可以使开发者使用完整的React语法来开发小程序。因为小程序框架本身是不支持js直接操作DOM的,那Remax框架是如何解决这个问题的呢?其实它自己复刻了一套操作DOM的API,例如appendChild,innterHtml等,但是它真正操作的并不是dom,而是data中的数据结构。从而达到了操作DOM的目的。使得自己真正成了一个运行时框架;

结语

介绍到这里,小程序的底层框架原理基本已经介绍完了,想跟大家分享的是,小程序确实和h5非常类似,其实它相当于一个借助了native强大功能的加强版h5,小程序并不神秘,除了微信小程序之外,现在各大超级APP都已经推出了自己的小程序,原理应该都大差不差。

本篇文章其实相当于一个学习笔记,作者本身非常想搞清楚微信小程序的架构,但是微信小程序并没有开源,某次偶然的机会逛掘金的时候看到这篇小册,就整个学习了一下,在此感谢原作者!

参考

https://juejin.cn/book/6982013809212784676?enter_from=course_center&utm_source=course_center

想了解更多转转公司的业务实践,点击关注下方的公众号吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/630116.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32F4_通过RS232实现和PC端通讯

目录 1. RS232通讯 2. 实验程序 2.1 main.c 2.2 RS232.c 2.3 RS232.h 通过上一节的学习,已经基本了解了RS232的通讯过程,实际上,不管是RS485还是RS232都是基于串口的一种通讯方式! STM32F4_RS485、RS232_light_2025的博客-CS…

[opencv]opencv-python环境搭建

删除源信息 conda config --remove-key channels 添加源 conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/msys2/ conda config --add chan…

ChatGPT 会带来失业潮吗?

(永久免费,扫码加入) 最近在翻知乎上的一些文章,很多都是跟ChatGPT有关的。因为本身是搞Python编程的,知乎推荐系统给我推荐了一篇廖雪峰老师的文章,觉得很有意思。 一共1119个赞,还是很厉害的&…

HTTPS 协议

哥几个来学 HTTPS 协议 啦 ~~ 目录 🌲一、HTTPS 是什么? 🌳二、何为 “加密” 🌴三、HTTPS 的工作过程 🍦1. 引入对称加密 🍧2. 引入非对称加密 🍨3.引入证书 🌲一、HTTPS 是什…

【前端 - HTML】第 4 课 - 列表标签

欢迎来到博主 Apeiron 的博客,祝您旅程愉快 ! 时止则止,时行则行。动静不失其时,其道光明。 目录 1、缘起 2、列表 3、无序列表 4、有序列表 5、定义列表 6、总结 1、缘起 微信小程序的列表标签是一种用于展示多个数据项的…

2023Java面试题库新合集,突击春招已助1000+人顺利入职大厂

前言: 互联网公司的面试,从形式上说,一般分为 2~3 轮技术面 1 轮 HR 面,不过某些公司没有 HR 面试。 在技术面试中,面试官一般会就你所应聘的岗位进行相关知识的考察,也叫基础知识和业务逻辑面试&#xf…

tp6用redis存储session

随着业务量的增加,很多时候会需要共享session的情况。共享session,其实就是说多台服务器共用一个session,或者是说一个主域跟多个子域之间共用一个session。工作中用tp也多一些,那么,我就用tp6来给大家讲解一下。 在共…

PyCharm显示python文件的函数和类的列表 structure视图的使用与介绍

目录 打开structure视图structure视图的使用与介绍1.排序方式按字母升序or降序排列2. 是否显示有关联的函数和类(一般不用激活)3. 展示类中的字段4. 点击后是否定位到目标5. 自动定位到当前文件 总结 欢迎关注 『Python』 系列,持续更新中 欢…

redolog与binlog为什么需要两阶段提交?

MySQL事务提交的时候,需要同时完成redo log和binlog的提交,为了保证两个日志的一致性,需要用到两阶段提交(与分布式的两阶段提交不同,这里的两阶段提交是发生在数据库内部) 数据库两阶段提交的流程 假设执行…

【P59】JMeter 用表格查看结果(View Results in Table)

文章目录 一、用表格查看结果(View Results in Table)参数说明二、准备工作三、测试计划设计 一、用表格查看结果(View Results in Table)参数说明 可以将取样器请求以表格的方式分析展示 使用场景:一般在调试测试计…

深入理解相机服务层 CameraService

和你一起终身学习,这里是程序员Android 经典好文推荐,通过阅读本文,您将收获以下知识点: 一、简介二、Camera AIDL 接口三、Camera Service 主程序 一、简介 Camera Service被设计成一个独立进程,作为一个服务端,处理来…

LIMS实验室信息管理系统源码 lims系统源码

一、LIMS概况 LIMS实验室管理系统是为实验、检测等业务板块提供流程化、模块化、标准化操作管理系统,打造基于行业法规的实验室全流程质量控制管理系统,实现实验室“人、机、料、法、环”关键环节管理。 二、技术框架说明 开发语言:C# 开…

是否需要更换CRM系统如何评估?如何确保更换成功?

很多企业在使用CRM客户管理系统的过程中,并没有达到预期的效果,甚至出现了实施失败的情况。部分企业可能会考虑更换CRM系统,以期获得更好的结果。但是,更换CRM系统是否值得呢?下面我们就来说说。 一、是否该更换CRM …

电容笔和触控笔两者的区别是什么?好用苹果电容笔推荐

如今,随着无纸化教育的兴起,电容笔也成为了人们关注的焦点。很多人对于电容笔和触控笔的区别很疑惑,其实,这两者是很好区分的,电容笔只能应用在我们最常用的电容屏上,例如我们的平板、手机屏幕等都是电容屏…

Redis 消息队列 Stream

tip:作为程序员一定学习编程之道,一定要对代码的编写有追求,不能实现就完事了。我们应该让自己写的代码更加优雅,即使这会费时费力。 💕💕 推荐:体系化学习Java(Java面试专题&#…

电脑技巧:Windows微信3.9.5更新一览

目录 01、新增锁定功能 02、可直接撤回正在发送的消息 03、翻译多个网页 04、搜一搜新增历史记录 05、视频号页面再次优化 近期,Windows微信又更新至3.9.5版本,新增了许多实用的功能,以下将对这些新功能进行介绍。 官方更新内容&#x…

mybatis-plus用法(一)

MyBatis-plus 是一款 Mybatis 增强工具,用于简化开发,提高效率。下文使用缩写 mp来简化表示 MyBatis-plus,本文主要介绍 mp 整合 Spring Boot 的使用。 (5条消息) mybatis-plus用法(二)_渣娃工程师的博客-CSDN博客 1…

【K哥爬虫普法】一个人、一年半、挣了2000万!

我国目前并未出台专门针对网络爬虫技术的法律规范,但在司法实践中,相关判决已屡见不鲜,K 哥特设了“K哥爬虫普法”专栏,本栏目通过对真实案例的分析,旨在提高广大爬虫工程师的法律意识,知晓如何合法合规利用…

2023免费版电脑视频剪辑软件会声会影

提到视频剪辑软件,浮现在我们脑海的可能就是满屏的功能键和眼花缭乱的操作界面。类似pr、AE之类的视频软件,操作界面看起来十分复杂,很多用户上手困难。而会声会影界面简单,功能齐全,也能完成专业级的视频制作。操作简…

基于SSM+JSP的疫情居家办公OA系统设计与实现

博主介绍: 大家好,我是一名在Java圈混迹十余年的程序员,精通Java编程语言,同时也熟练掌握微信小程序、Python和Android等技术,能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架下…