本文将从以下几个方面来说一下小程序的实现原理
小程序的架构设计与web技术还是有一定的差别,其吸取了web技术的一些优势,同时也摒弃web技术中体验等不好的地方。下面通过问题的形式来说说小程序架构中的一些设计点。
开发过小程序的都知道,小程序是双线程设计,即视图渲染与业务逻辑分别在运行在不同的线程中。这个设计主要是解决web技术中的一个痛点:
小程序为了更好体验,将页面的渲染线程和脚本线程分开设计在不同线程中执行,具体实现:
页面渲染的方式主要有三种:
界面主要由成熟的Web技术渲染,辅之以大量的接口提供丰富的客户端原生能力。同时,每个小程序页面都是用不同的WebView去渲染,这样可以提供更好的交互体验,更贴近原生体验,也避免了单个WebView的任务过于繁重。既然采用Hybrid方式渲染,那么页面的渲染可能会用到原生native来渲染,什么情况会用到原生渲染呢?
上面说到小程序主要由成熟的web技术渲染,能否直接使用html提供的标签如div、table等组织页面呢,答案不可以。主要考量:
所以,小程序不能直接使用html标签渲染页面,其提供了10多个内置组件来收敛web标签,并且提供一个JavaScript沙箱环境来避免js访问任何浏览器api。
既然小程序不能直接使用html标签来渲染页面,那它提供的如view、cover-view等内置组件是否意味着最终都转换为html提供的内置标签来渲染呢?答案当不是。我们来看如下代码:
可以看出,小程序提供的组件并没有最终转换为为html对应的标签来渲染,而是使用自定义的元素来渲染。这些内置组件都是由Exparser框架负责管理,它内置在小程序基础库中,为小程序的各种组件提供基础的支持。
那么问题来了,小程序是怎么给业务代码加上以上封装的呢?其实很简单,在小程序开发者工具中有一个后台服务,访问小程序的每个模块的path时,后台服务会调用wrapSourceCodeInDefine方法将请求的JS文件的内容分别包裹在define域中,方法的代码如下图所示:
这里的define是小程序底层实现模块化的方法之一,还有一个是require方法;通过define来定义一个模块,require来引用一个define定义的模块。从上面小程序对业务模块代码的封装可以看出:
业务代码无法访问dom,怎么实现页面动态更新呢?
答案就是采用类vue这种MVVM框架的数据驱动思想,即让视图状态和视图绑定在一起,状态变更时,视图也能自动变更,这样就不用直接操作dom。
视图的动态更新具体是采用virtualdom技术实现,virtualDOM相信大家都已有了解,大概是这么个过程如下图:
实际处理可以简单描述如下:
用JS对象模拟DOM树->比较两棵虚拟DOM树的差异->把差异应用到真正的DOM树上。
其中,virtualdom是通过内置的wcc可以将wxml转换为js对象形式,以此来表示DOM树结构。
下面以官网的一幅图来说视图动态更新的过程:
我们在开发者工具开发小程序时,一般都会选择一个基础库,如小程序开发者工具选择界面:
小程序基础库是用JavaScript写的,但是我们并没有在我们的小程序中直接引用,那么我们是怎么使用基础库提供功能的呢?答案是:
小程序基础库功能包括两个部分视图层的WAWebview.js和业务逻辑层的WAService.js。下面就简单说下对应功能:
下看看一下WAService.js源码内容缩略图:
从源码可以看出基础库提供的WAService.js有很多功能,主要包括以下几部分
小程序基础库为视图层提供的基础功能有些与WAService相同,主要功能如下: