关于小程序的一切,读这一篇就够了~

| 2017.1 | 2018.7 | 2018.9 | 2019.6 |

基于小程序几乎相同的技术原理,以及小程序的方便快捷的特性,还衍生出了多款小程序,比如抖音小程序、快手小程序、京东小程序、美团小程序等,帮助各大厂商更好的为用户提供便捷的服务。

2018 年微信小程序 “跳一跳” 爆火,记得当年食堂排队打饭的时候很多同学都在玩,助力了微信小程序在用户中的扩张,也激发了其他厂商开发小程序的热潮。

图片

2. 原理分析

============

2.1 双线程模型


无论是微信小程序还是支付宝小程序还是百度智能小程序等等,他们的总体架构都是基于双线程的。

图片

其中用于处理业务逻辑的 JS 代码运行在单独的线程里,渲染层(template、css)则运行在另外一个单独的线程里。

以微信小程序为例:

图片

双线程模型不同于单线程模型,逻辑层与渲染层的数据交互需要通过 JSBridge,二者是通过发布订阅,基于当前比较比较著名的 MVVM,来实现数据的双向绑定的,从而实现数据通信。

这样我们在微信小程序中通过在逻辑层中 setData 来改变 Model 层的数据就能够实现视图数据的异步更新。

图片

以下是微信小程序的生命周期:

图片

2.2 整体架构


图片

注:以下所有内容均围绕微信开发者工具展开。

打开微信开发者工具的源代码,他是基于 NW.js 运行的,所以下图中的 package.nw 就是我们要重点钻研的对象:

图片

这里面有很多代码,都是经过混淆与压缩的,将代码在 VSCode 中打开,并安装 Prettier - Code formatter 插件可以实现对源码的格式化。但此时代码中已经不具有语义化的变量了,只能通过 API 大致推断代码是干什么的。

源码中有一个 vendor 文件夹是值得注意的,通过它可以快速新建一个示例项目,同时里面有一个十分重要的 2.17.0.wxvpkg 包,它是微信小程序的基础库,包含了下文所提及的 WebService 与 WebView 等逻辑层与渲染层的处理。

图片

2.2.1 WAWebview

小程序视图层基础库,提供视图层的基础能力:

var __wxLibrary = {

fileName: ‘WAWebview.js’,

envType: ‘WebView’,

contextType: ‘others’,

execStart: Date.now()

};

var WAWebviewStartTime = Date.now();

var libVersionInfo = {

“updateTime”: “2020.4.4 10:25:02”,

“version”: “2.10.4”

};

/**

  • core-js 模块

*/

!function(n, o, Ye) {

}, function(e, t, i) {

var n = i(3),

o = “core-js_shared”,

r = n[o] || (n[o] = {});

e.exports = function(e) {

return r[e] || (r[e] = {})

}

}(1, 1);

var __wxConfig;

var wxTest = false;

var wxRunOnDebug = function(e) {

e()

};

/**

  • 基础模块

*/

var Foundation = function(i) {

}]).default;

var nativeTrans = function(e) {

}(this);

/**

  • 消息通信模块

*/

var WeixinJSBridge = function(e) {

}(this);

/**

  • 监听 nativeTrans 相关事件

*/

!function() {

}();

/**

  • 解析配置

*/

!function® {

__wxConfig = _(__wxConfig), __wxConfig = v(__wxConfig), Foundation.onConfigReady(function() {

m()

}), n ? __wxConfig.__readyHandler = A : d ? Foundation.onBridgeReady(function() {

WeixinJSBridge.on(“onWxConfigReady”, A)

}) : Foundation.onLibraryReady(A)

}(this);

/**

  • 异常捕获(error、onunhandledrejection)

*/

!function(e) {

function t(e) {

Foundation.emit(“unhandledRejection”, e) || console.error(“Uncaught (in promise)”, e.reason)

}

“object” == typeof e && “function” == typeof e.addEventListener ? (e.addEventListener(“unhandledrejection”, function(e) {

t({

reason: e.reason,

promise: e.promise

}), e.preventDefault()

}), e.addEventListener(“error”, function(e) {

var t;

t = e.error, Foundation.emit(“error”, t) || console.error(“Uncaught”, t), e.preventDefault()

})) : void0 === e.onunhandledrejection && Object.defineProperty(e, “onunhandledrejection”, {

value: function(e) {

t({

reason: (e = e || {}).reason,

promise: e.promise

})

}

})

}(this);

/**

  • 原生缓冲区

*/

var NativeBuffer = function(e) {

}(this);

var WeixinNativeBuffer = NativeBuffer;

var NativeBuffer = null;

/**

  • 日志模块:wxConsole、wxPerfConsole、wxNativeConsole、webviewConsole

*/

var wxConsole = [“log”, “info”, “warn”, “error”, “debug”, “time”, “timeEnd”, “group”, “groupEnd”].reduce(function(e, t) {

return e[t] = function() {}, e

}, {});

var wxPerfConsole = [“log”, “info”, “warn”, “error”, “time”, “timeEnd”, “trace”, “profile”, “profileSync”].reduce(function(e, t) {

return e[t] = function() {}, e

}, {});

var wxNativeConsole = function(i) {

}([function(e, t, i) {

}]).default;

var webviewConsole = function(i) {

}([function(e, t, i) {

}]);

/**

  • 上报模块

*/

var Reporter = function(i) {

}([function(e, L, O) {

}]).default;

var Perf = function(i) {

}([function(e, t, i) {

}]).default;

/**

  • 视图层 API

*/

var webViewSDK = function(i) {

}([function(e, L, O) {

}]).default;

var wx = webViewSDK.wx;

/**

  • 组件系统

*/

var exparser = function(i) {

}([function(e, t, i) {

}]);

/**

  • 框架粘合层

  • 使用 exparser.registerBehavior 和 exparser.registerElement 方法注册内置组件

  • 转发 window、wx 对象上到事件转发到 exparser

*/

!function(i) {

}([function(e, t) {

}, function(e, t) {}, , function(e, t) {}]);

/**

  • Virtual DOM

*/

var virtualDOMDataThread = false;

var virtualDOM = function(i) {

}([function(e, t, i) {

}]);

/**

  • webviewEngine

*/

var webviewEngine = function(i) {

}([function(e, t, i) {

}]);

/**

  • 注入默认样式到页面

*/

!function() {

function e() {

var e = i(‘…’);

__wxConfig.isReady ? void0 !== __wxConfig.theme && i(t, e.nextElementSibling) : __wxConfig.onReady(function() {

void0 !== __wxConfig.theme && i(t, e.nextElementSibling)

})

}

window.document && “complete” === window.document.readyState ? e() : window.onload = e

}();

var WAWebviewEndTime = Date.now();

typeof __wxLibrary.onEnd === ‘function’ && __wxLibrary.onEnd();

__wxLibrary = undefined;

WAWebview 主要由以下几个部分组件:

  • Foundation:基础模块

  • WeixinJSBridge:消息通信模块

  • exparser:组件系统模块

  • __virtualDOM__:Virtual DOM 模块

  • __webViewSDK__:WebView SDK 模块

  • Reporter:日志上报模块 (异常和性能统计数据)

2.2.2 WAService

小程序逻辑层基础库,提供逻辑层基础能力:

var __wxLibrary = {

fileName: ‘WAService.js’,

envType: ‘Service’,

contextType: ‘App:Uncertain’,

execStart: Date.now()

};

var WAServiceStartTime = Date.now();

(function(global) {

var exportGlobal = {};

var libVersionInfo = {

“updateTime”: “2020.4.4 10:25:02”,

“version”: “2.10.4”

};

var Function = global.Function;

var Function = Function;

/**

  • core-js 模块

*/

!function(r, o, Ke) {

}(1, 1);

var wxTest = false;

var wxRunOnDebug = function(e) {

e()

};

var __wxConfig;

/**

  • 基础模块

*/

var Foundation = function(n) {

}([function(e, t, n) {

}]).default;

var nativeTrans = function(e) {

}(this);

/**

  • 消息通信模块

*/

var WeixinJSBridge = function(e) {

}(this);

/**

  • 监听 nativeTrans 相关事件

*/

!function() {

}();

/**

  • 解析配置

*/

!function(i) {

}(this);

/**

  • 异常捕获(error、onunhandledrejection)

*/

!function(e) {

}(this);

/**

  • 原生缓冲区

*/

var NativeBuffer = function(e) {

}(this);

WeixinNativeBuffer = NativeBuffer;

NativeBuffer = null;

var wxConsole = [“log”, “info”, “warn”, “error”, “debug”, “time”, “timeEnd”, “group”, “groupEnd”].reduce(function(e, t) {

return e[t] = function() {}, e

}, {});

var wxPerfConsole = [“log”, “info”, “warn”, “error”, “time”, “timeEnd”, “trace”, “profile”, “profileSync”].reduce(function(e, t) {

return e[t] = function() {}, e

}, {});

var wxNativeConsole = function(n) {

}([function(e, t, n) {

}]).default;

/**

  • Worker 模块

*/

var WeixinWorker = function(e) {

}(this);

/**

  • JSContext

*/

var JSContext = function(n) {

}([

}]).default;

var appServiceConsole = function(n) {

}([function(e, N, R) {

}]).default;

var Protect = function(n) {

}([function(e, t, n) {

}]);

var Reporter = function(n) {

}([function(e, N, R) {

}]).default;

var subContextEngine = function(n) {

}([function(e, t, n) {

}]);

var waServiceInit = function() {

}

function doWAServiceInit() {

var e;

“undefined” != typeof wx && wx.version && (e = wx.version), waServiceInit(), e && “undefined” != typeof exportGlobal && exportGlobal.wx && (exportGlobal.wx.version = e)

}

subContextEngine.isIsolateContext();

subContextEngine.isIsolateContext() || doWAServiceInit();

subContextEngine.initAppRelatedContexts(exportGlobal);

})(this);

var WAServiceEndTime = Date.now();

typeof __wxLibrary.onEnd === ‘function’ && __wxLibrary.onEnd();

__wxLibrary = undefined;

WAService 基本组成:

  • Foundation:基础模块

  • WeixinJSBridge:消息通信模块

  • WeixinNativeBuffer:原生 Buffer

  • WeixinWorker:Worker 线程

  • JSContext:JS Engine Context

  • Protect:JS 保护的对象

  • __subContextEngine__:提供 App、Page、Component、Behavior、getApp、getCurrentPages 等方法

2.2.3 虚拟 DOM

微信小程序在 WAService 里面实现了小程序的 __virtualDOM__,通过 __virtualDOM__ 模块,可以实现 JS 对象到 DOM 对象的映射。

但是这个虚拟 DOM 通过 diff 和 patch 后并不是转换成原生的 DOM 元素,而是微信小程序里面自定义的 DOM 元素,这些 DOM 元素的操作通过 Exparser 模块来统一管理:

在 WAWebview 中包含了所有的 wx 自定义标签:

图片

同时,__virtualDOM__ 模块提供了很多的基础 API,比如:

  • getAll:获取所有 Node

  • getNodeById:根据 Id 获取 Node

  • getNodeId:获取 NodeId

  • addNode:添加节点

  • removeNode:删除节点

  • getExparser:获取 Exparser 对象(基于 WebComponent 的 shadow DOM 模型,可以在 JS 环境中运行,所有与节点树相关的操作都依赖于他)

(更多的 API 定义可以在 WAService.js 里面去查询)

2.2.4 WeiXinJSBridge

WeixinJSBridge 提供了视图层 JS 与 Native、视图层与逻辑层之间消息通信的机制,提供了如下几个方法:

里面最重要的便是 on 和 invoke,通过 on 来注册事件,通过 invoke 来触发相应的事件。

2.3 微信开发者工具


微信开发者工具中的小程序是跑在 NW.js 中的,这里是他的官方 API 文档:https://nwjs.readthedocs.io/en/latest/

他是基于 Chromium 和 Node.js 的,因此我们编译后的虚拟 DOM 转换成真实 DOM 后,通过他来运行。

2.3.1 一些反编译技巧

我们可以通过开发者工具,在 Devtools 里输入 help 可以得到很多指令:

图片

其中比较有用的是 openVendor。这个函数可以打开当前项目的源码,其实也就是包含了 wcc 和 wcsc 编译工具的一个文件夹:

有了这些文件之后,对我们之后的分析会很有帮助。

我们可以将这些文件拷贝到一个单独的目录,在 VSCode 中打开该项目,并安装以下插件:

图片

这个插件可以将微信开发者工具中的所有以 .wxvpkg 结尾的文件进行解压缩。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

知其然不知其所以然,大厂常问面试技术如何复习?

1、热门面试题及答案大全

面试前做足功夫,让你面试成功率提升一截,这里一份热门350道一线互联网常问面试题及答案助你拿offer

2、多线程、高并发、缓存入门到实战项目pdf书籍

3、文中提到面试题答案整理

4、Java核心知识面试宝典

覆盖了JVM 、JAVA集合、JAVA多线程并发、JAVA基础、Spring原理、微服务、Netty与RPC、网络、日志、Zookeeper、Kafka、RabbitMQ、Hbase、MongoDB 、Cassandra、设计模式、负载均衡、数据库、一致性算法 、JAVA算法、数据结构、算法、分布式缓存、Hadoop、Spark、Storm的大量技术点且讲解的非常深入


《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

知其然不知其所以然,大厂常问面试技术如何复习?

1、热门面试题及答案大全

面试前做足功夫,让你面试成功率提升一截,这里一份热门350道一线互联网常问面试题及答案助你拿offer

[外链图片转存中…(img-JLajLlg2-1713531529885)]

2、多线程、高并发、缓存入门到实战项目pdf书籍

[外链图片转存中…(img-BKckdeTj-1713531529885)]

[外链图片转存中…(img-7pUvPKN2-1713531529885)]

[外链图片转存中…(img-B01dm78e-1713531529885)]

3、文中提到面试题答案整理

[外链图片转存中…(img-owZ4WWQD-1713531529885)]

4、Java核心知识面试宝典

覆盖了JVM 、JAVA集合、JAVA多线程并发、JAVA基础、Spring原理、微服务、Netty与RPC、网络、日志、Zookeeper、Kafka、RabbitMQ、Hbase、MongoDB 、Cassandra、设计模式、负载均衡、数据库、一致性算法 、JAVA算法、数据结构、算法、分布式缓存、Hadoop、Spark、Storm的大量技术点且讲解的非常深入

[外链图片转存中…(img-6G1KK1Pv-1713531529886)]

[外链图片转存中…(img-JL6rL6wy-1713531529886)]

[外链图片转存中…(img-BLEx9j7H-1713531529886)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 13
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值