概述
小程序的 Http Rquest 请求是不是用的浏览器 Fetch API?
不是, http request是由逻辑层发起,通过native去触发的,且不支持promise。
小程序渲染再同一个线程么?
小程序是双线程设计,即视图渲染与业务逻辑分别在运行在不同的线程中。这个设计主要是解决web技术中的一个痛点:
web页面开发渲染线程和脚本线程是互斥的,长时间的脚本运行可能会导致页面失去响应或者白屏,体验糟糕。
小程序为了更好体验,将页面的渲染线程和脚本线程分开设计在不同线程中执行,具体实现:
● 视图view层在webview中渲染,一个页面对应一个webview
● 业务逻辑Appservice层运行在同一个JSCore线程中,具体ios是JavaScriptCore,android是X5 JSCore,开发者工具是webview中;
这样解决了长时间的脚本阻塞页面渲染的情况,但是也带来一些新的问题:
● 天生的延迟,线程间要通信
● 业务逻辑层因为运行在JSCore中无法访问DOM和BOM的api;
开发者工具使用webview加载业务逻辑层的代码,虽然依赖的环境有DOM和BOM api,为了保持一致;小程序对所有的模块进行了局部化处理使其不能访问这些api。这样双线程通过native,开发者工具通过后台websocket服务充当二者消息中转媒介,并且提供一些基础功能。
为什么要采用这种技术方案呢?
主要原因是小程序的管控限制,比如不能直接操作DOM树、页面跳转等管控措施,更好地形成自己的生态闭环。
启动过程
背景
它依托浏览器(webview)展示,同时可以调用原生能力(如获取通信录,拍照等等),同一份代码可运行在Android,iOS和微信调试开发工具内(跨平台能力)。
与RN的跨平台不同,小程序大部分UI组件并不是原生渲染,还是类似web app用浏览器渲染。只有少量组件是Native实现(Native组件层在WebView层之上): <canvas/> <video/> <map/> <textarea/>
架构
展现层:这是小程序的页面显示,包括菜单、标题等展示内容
控制层:包括 UI 控制、中枢控制
消息处理层:包含了通信消息分发处理、缓存
服务层就是包括网络、存储、文件等服务还可以看到,基础设施层包括日志文件、数据存储
基础本地层是访问本身设备相机通讯等功能
操作系统层就是运行载体平台,比如 ios、Android
线程名称 | 所属模块 | 运行代码 | 原理 | 备注 |
---|---|---|---|---|
View | 视图层(可能有多个) | WXML/WXSS | webview渲染 | wxml编译器把wxml文件转为js(构建virtual dom);wxss编译器把wxss文件转化为js |
AppService | 逻辑层(一个) | JS | JavascriptCore运行 | 无法访问 window/document对象 |
iOS :小程序逻辑层的 JavaScript 代码运行在 JavaScriptCore() 中,视图层是由 WKWebView 来渲染的
Android:小程序逻辑层的JavaScript 代码运行在 V8 中,视图层是由自研 XWeb 引擎基于 Mobile( )Chrome() 内核来渲染的
开发工具:小程序逻辑层的JavaScript 代码是运行在 NW.js 中,视图层是由 Chromium() Webview 来渲染的
那么,两个模块之间如何通信呢?
视图层触发事件通过 JSBridage 传给逻辑层,逻辑层处理后将数据通过 JSBridage 传给视图层。
所以:
- 小程序中的 js 无法操作 dom,因为不在一个线程。如果需要在 View Thread 中运行自定义js代码,可以使用wxs(微信开发的脚本语言),它和View同一个线程。
页面
在宿主应用中打开小程序时,会将小程序的代码包先下载到本地,然后通过解析 app.json 里的 pages 字段,就可以知道该小程序的所有页面路径
pages 数组中的第一个值,就是小程序打开时看到的第一个页面。而每个页面的路径,在程序代码包里都可以找到对应的文件路径。
例如 pages/index/index,在该路径下,存在着这个页面对应的 WXML、WXSS 与 JS 文件。小程序启动后,就会根据这个路径找到对应页面中的代码文件,再交给逻辑层和视图层执行,于是我们就可以在宿主 App 上看到这个小程序的页面了。
当小程序启动之后,就会触发 app.js 中定义的 onLaunch 方法
在 index.js 文件里 Page({...})
会构造出 index 页面实例,data 表示的是该页面需要用到的渲染数据。当生成页面时,小程序引擎会把 data 数据和 index.wxml 结合,再渲染出来显示给用户。
onLoad() 方法则是页面的生命周期方法,页面创建时会回调该方法
加载过程
在宿主应用中打开小程序时
1、会将小程序的代码包先下载到本地
2、解析 app.json 里的 pages 字段,就可以知道该小程序的所有页面路径
3、解析 pages 数组得到所有小程序的页面路径,每个页面路径都有对应的 WXML、WXSS 与 JS 文件。数组中第一个为首页。
4、将代码交给逻辑层和视图层执行,就可以在宿主 App 上看到这个小程序的页面了。
冷启动热启动
通常,只有当小程序进入后台一定时间,或者系统资源占用过高,才会被销毁,移动端小程序的销毁机制如下:
当小程序占用系统资源过高,可能会被系统销毁或被客户端主动回收。
在 iOS 上,最多允许有 5 个小程序 同时存在,如果超过 5 个会销毁最久未被使用的那个小程序。此外当客户端收到内存告警时,会主动进行所有后台小程序的销毁。
在 Android 上,最多允许有 5 个小程序 同时存在,如果超过 5 个会销毁最久未被使用的那个小程序。此外当内存不足时,系统会直接回收内存,销毁后台长时间未使用的小程序。
源码分析
在 console 里输入
document.getElementsByTagName('webview')[0].showDevTools(true,null)
则打开另一个调试窗口,这个窗口就是这个 webview 的详细介绍
可以看到结构和 wxml 里的内容几乎一模一样,只是view 变成了 wx-view等。这些都是内部实现的一套对应小程序标签的 webComponent 组件,而 webComponent 实际渲染出来还是 html 标签。
上面我们查看了逻辑层的代码,如果要查看渲染层呢?
刚刚的console 中输入 document
wcc (一段脚本)将微信小程序设计的一套wxml标签语言,用于构建出页面结构,转为WebView可以理解的标签,毕竟渲染层还是运行在webview中,我们可以通过一张图来看下它的编译流程。
- 先加载小程序所有页面中wxml格式的文件代码
- 将它们转换成一个$gwx(pagePath)的js函数,注入到webview中
- 在小程序运行时,可以知道当前的页面路径,执行这个函数会生成该页面的结构函数,之后接受页面数据,输出一段描述页面结构的virtual() dom json对象
- 最后通过小程序内部组件生成页面对应的HTML标签,页面标签通过wcc编译转化成我们熟悉的节点。
wcsc (一段脚本)负责把wxss内容转换为视图可使用的css内容,它同时会分析文件之间的引用关系,添加尺寸单位rpx转换,还能根据屏幕宽度自适应以及样式导入,最后会生成一个eval()()函数用于处理rpx,输出一个样式信息数组。
之后创建 style 标签,动态添加到视图层中
小程序的基础库
- WAWebview:小程序视图层基础库,提供视图层基础能力
- WAService:小程序逻辑层基础库,提供逻辑层基础能力
微信小程序基础库更新过程可能会对基础库有些变更,下面就 v2.12.2 版本对基础库进行分析:
WAWebview 源码结构
WAWebview 主要由以下几个部分组件:
Foundation: 基础模块
WeixinJSBridge: 消息通信模块
exparser: 组件系统模块
virtualDOM: Virtual DOM 模块
webViewSDK: WebView SDK 模块
Reporter: 日志上报模块(异常和性能统计数据)
WAService 源码结构
WAService 基本组成:
Foundation: 基础模块
WeixinJSBridge: 消息通信模块
appServiceEngine:用于定义页面全局的方法,如define,require, App,Page,Component,getApp等
WeixinNativeBuffer: 原生 Buffer
WeixinWorker: Worker 线程
JSContext: JS Engine Context
Protect: JS 保护的对象
subContextEngine: 提供 App、Page、Component、Behavior、getApp、getCurrentPages 等方法
数据通信
可以理解AppService即一个简单的页面,主要功能是负责逻辑处理部分的执行,底层提供一个WAService.js的文件来提供各种api接口,主要是以下几个部分:
消息通信封装为WeixinJSBridge(开发环境为window.postMessage, IOS下为WKWebview的window.webkit.messageHandlers.invokeHandler.postMessage,android下用WeixinJSCore.invokeHandler)
1、日志组件Reporter封装
2、wx对象下面的api方法
3、全局的App,Page,getApp,getCurrentPages等全局方法
4、还有就是对AMD模块规范的实现
然后整个页面就是加载一堆JS文件,包括小程序配置config,上面的WAService.js(调试模式下有asdebug.js),剩下就是我们自己写的全部的js文件,一次性都加载。
service 线程其实就是空的webview 加载很多 js 文件。
小程序的基础库不会被打包在某个小程序代码包里,而是内置在微信客户端。
打包后的小程序结构
1、WAService.js 框架JS库,提供逻辑层基础的API能力
2、WAWebview.js 框架JS库,提供视图层基础的API能力
3、WAConsole.js 框架JS库,控制台
4、app-config.js 小程序完整的配置,包含我们通过app.json里的所有配置,综合了默认配置型
5、app-service.js 我们自己的JS代码,全部打包到这个文件
6、page-frame.html 小程序视图的模板文件,所有的页面都使用此加载渲染,且所有的WXML都拆解为JS实现打包到这里
7、pages 所有的页面,这个不是我们之前的wxml文件了,主要是处理WXSS转换,使用js插入到header区域。
参考资料
https://cloud.tencent.com/developer/article/1029663
https://cloud.tencent.com/developer/article/1773703
https://blog.csdn.net/weixin_34133829/article/details/88827942
https://www.finclip.com/mop/document/develop/guide/host-environment.html
小程序原理(一):渲染与通信
微信小程序实现原理
小程序实现原理解析
最后
以上就是美好汽车为你收集整理的小程序底层原理的全部内容,希望文章能够帮你解决小程序底层原理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复