# 什么是小程序
小程序是一种不需要安装即可使用的应用,它实现了应用 “触手可及” 的梦想。用户扫一扫或者搜一搜即可打开应用,也体现了 “用完即走” 的理念。用户不用关心是否安装太多应用的问题,应用将无处不在,随时可用,但又无需安装卸载。因此,它具有以下特点:
体验好
开发成本低,一次开发,多端共享
离线缓存(10M)
接口更多(相比订阅号及服务号)
# 小程序和其他应用的区别
# 小程序和 App 的区别
无需安装
不占内存
易传播
# 小程序和 Native App、WebApp 以及 Hybrid App 的区别
# 小程序与普通网页开发的区别
开发语言不同
多线程,在小程序中,逻辑层和视图层是分开的,分别运行在两个不同的线程中
在小程序中没有浏览器里的 Dom API 和 Bom API
运行环境不同
# 小程序的运行环境
补充
NW.js (opens new window) 全称是 Node-Webkit JS,通过使用页面相关技术开发桌面应用, 同时能够使用 DOM 调用 Node.js 的所有模块。
NW.js 英文文档 (opens new window)、NW.js 中文文档 (opens new window)
同样开发桌面应用的还有另外一种更常用的技术栈:Electron (opens new window),它是使用 JavaScript,HTML 和 CSS 来构建跨平台的桌面应用程序的框架。VSCode 就是用它开发的。
# 开发小程序的前置准备
- 每一个小程序/公众号/小游戏都需要一个 email,同一个手机号只能注册 5 个,同一个身份证也只能注册 5 个。普通开发者注册个人版就可以了,但有些极个别的类目,个人做不了。
建议
建议去看看微信小程序的运营规范 (opens new window),这里面规定了可以开发哪些类型的小程序,不能开发哪些类型的小程序,如果我们不看,产品经理也没看,最后开发出来审核不通过,被坑的就是我们自己。
# 小程序的开发技巧
# 导航跳转
小程序中实现跳转的方式是通过 navigator (opens new window) 组件和路由 API wx.navigateTo (opens new window)。
小程序中页面栈最多 10 层,同时每个小程序可跳转的其他小程序数量限制为不超过 10 个。
# 服务器域名配置
每个微信小程序需要事先设置通讯域名 (opens new window),小程序只可以跟指定的域名进行网络通信。包括普通 HTTPS 请求(wx.request (opens new window))、上传文件(wx.uploadFile (opens new window))、下载文件(wx.downloadFile (opens new window))和 WebSocket 通信(wx.connectSocket (opens new window))。
服务器域名请在小程序后台-开发-开发管理-开发设置-服务器域名中进行配置。
不过,在微信开发者工具中,也可以临时配置跳过服务器域名的校验。
# 添加编译模式
微信开发者工具中默认显示的页面是 app.json 中 pages 数组里的第一项所对应的页面。如果我们想调试某个页面,但是这个页面又不在 pages 里第一个位置,我们除了可以临时将需要调试的页面放到第一项之外,还可以通过添加编译模式的方法来使开发者工具默认显示我们需要调试的页面。添加方法如下:
将模式名称和启动页面改成我们当前需要调试的页面路径就可以了。
# 获取当前页面栈
我们可以使用 getCurrentPages() (opens new window) 函数来获取当前页面栈。
# 查看 webview
webview (opens new window) 是承载网页的容器。
每个页面只能有一个 webview,会自动铺满整个小程序页面,个人类型的小程序暂不支持使用。
客户端 6.7.2 版本开始,navigationStyle: custom 对 web-view 组件无效。
webview 网页内 iframe 的域名也需要配置到域名白名单。
避免在链接中带有中文字符,在 iOS 中会有打开白屏的问题,建议加一下 encodeURIComponent。
首先打开调试微信开发者工具
然后,在弹出来的调试器中输入以下命令,就可以看到当前开发者工具中 webview 的数量。注意微信开发者工具本身是由 4 个 webview 组成的。
document.getElementsByTagName("webview");
接着,还可以通过以下命令查看具体某个 webview 中的 html 内容。
document.getElementsByTagName("webview")[0].showDevTools(true);
# 查看基础库
在微信开发者工具的详情中可以看到各个版本的基础库 (opens new window)。
同时,在 windows 的微信开发者工具的控制台中,输入以下命令能够直接打开本地的基础库文件夹,但是 mac 中却不行。
openVendor();
# 查看页面的 js 对象表示
$gwx("./pages/index/index.wxml")({ show: true });
# 小程序的渲染方式
页面渲染的方式主要有三种:
纯 web 渲染
纯 native 原生渲染
Hybird 混合渲染,即 web 和 native 渲染结合
微信小程序使用的就是混合渲染。
# 小程序的基础架构
整个小程序系统构架分成两个部分:视图层(WebView)和逻辑层(App Service),这两个部分分别由两个独立线程管理。
视图层:也称为渲染层,渲染层用来渲染页面结构,主要由 WebView 进行渲染,一个小程序可以存在多个界面,所以渲染层可能存在多个 WebView 线程。
逻辑层:逻辑层采用 JSCore 线程运行 JS 脚本。逻辑层主要用来逻辑处理、数据请求、接口调用等。
视图层和逻辑层之间的沟通则需要借助系统层(WeixinJsBridage,简称 JSBridage)进行通信,逻辑层把数据变化通知到视图层,触发视图层页面更新,视图层把触发的事件通知到逻辑层进行业务逻辑处理。
evaluateJavascript
视图层和逻辑层通信是借助了系统层的作用,而实际上是通过两边提供的 evaluateJavascript 所实现的。即用户传输的数据,需要将其转换为字符串形式传递,同时把转换后的数据内容拼接成一份 JS 脚本,再通过执行 JS 脚本的形式传递到两边独立环境。
Native 调用 JS,一般就是直接 JS 代码字符串,有点类似我们调用 JS 中的 eval 去执行一串代码。它一般有 loadUrl、evaluateJavascript 等几种方法。
JSBridge 起到了一个中间桥梁的作用,非常重要。它不仅让视图层与逻辑层两个单独线程能进行通信,而且也架起上层开发与系统底层功能(Native)的桥梁,使得小程序可以通过调用 API 使用原生功能,且部分组件用原生组件实现,从而有良好体验。
页面渲染大致过程为:
项目进行编译会把 WXML 转化成对应的 JS 对象(Virtual DOM),在逻辑层发生数据变化的时候,会通过 setData() 方法把数据从逻辑层传递到视图层,视图层在接收到数据后,会在内部进行差异对比,把差异应用在原来的 Dom 树上,再正确的渲染出 UI 界面,完成页面的渲染过程。
逻辑层发送网络请求都是经由系统层进行转发的。
# 小程序的运行机制
小程序启动运行有两种情况:
冷启动(重新开始):用户首次打开或者小程序被微信主动销毁后再次打开的情况,此时小程序需要重新加载启动,即为冷启动。
热启动:用户已经打开过小程序,然后在一定时间内再次打开该小程序,此时无需重新启动,只需要将后台态的小程序切换到前台,这个过程就是热启动。
注意
小程序没有重启的概念。
当小程序进入后台,客户端会维持一段时间的运行状态,超过一定时间后会被微信主动销毁。
短时间内收到系统两次以上内存警告,也会对小程序进行销毁,这也就为什么一旦页面内存溢出,页面会奔溃的本质原因了。
# 小程序冷启动的步骤
# 1. 启动小程序应用
用户点击小程序图标或通过其他入口进入小程序,触发小程序的启动。
# 2. 下载小程序代码包
如果用户首次打开小程序或小程序代码包有更新,微信客户端会从远程服务器下载小程序的代码包。
小程序代码包通常包含了小程序的逻辑代码、页面结构、样式等。
# 3. 解析小程序代码
下载完成后,微信客户端开始解析小程序的代码,构建 DOM 树,生成页面结构。
# 4. 初始化小程序环境
初始化小程序的运行环境,包括初始化全局数据、配置信息、注册事件处理函数等。
执行小程序生命周期中的 onLaunch 钩子函数,用于进行一些全局性的初始化工作。
# 5. 渲染首屏页面
将解析后的页面结构渲染到用户的设备屏幕上,显示小程序的首屏内容。
这可能包括网络请求,以获取首屏所需的数据。
# 6. 加载和执行小程序脚本
执行小程序的逻辑代码,处理用户的操作和事件响应。
运行小程序生命周期中的 onShow 钩子函数,表示小程序已经展示在用户面前。
# 7. 预加载其他页面
为了提高用户体验,微信客户端可能会在冷启动时预加载其他页面的代码,以便在用户切换页面时能够更快地展示内容。
# 8. 执行其他生命周期钩子
随着小程序的运行,可能会触发其他生命周期钩子函数,例如 onHide、onUnload 等,用于处理小程序在前台和后台的切换。
# 小程序热启动的步骤
# 1. 启动小程序应用
用户再次点击小程序图标或通过其他入口再次进入小程序,触发小程序的启动。
# 2. 检查代码包更新
微信客户端首先检查小程序的代码包是否有更新。如果有更新,将会下载最新的代码包。
# 3. 解析小程序代码
如果有新的代码包,微信客户端开始解析新代码,构建 DOM 树,生成页面结构。
如果代码包没有更新,可能会直接使用缓存的解析结果,加速渲染过程。
# 4. 初始化小程序环境
初始化小程序的运行环境,包括全局数据、配置信息、注册事件处理函数等。
执行小程序生命周期中的 onLaunch 钩子函数,用于进行一些全局性的初始化工作。
# 5. 渲染首屏页面
将解析后的页面结构渲染到用户的设备屏幕上,显示小程序的首屏内容。
这可能包括了缓存的网络请求结果,以及预加载的其他页面的部分内容。
# 6. 加载和执行小程序脚本
执行小程序的逻辑代码,处理用户的操作和事件响应。
运行小程序生命周期中的 onShow 钩子函数,表示小程序已经展示在用户面前。
# 7. 预加载其他页面
为了提高用户体验,微信客户端可能会在热启动时预加载其他页面的代码,以便在用户切换页面时更快地展示内容。
# 8. 执行其他生命周期钩子
随着小程序的运行,可能会触发其他生命周期钩子函数,例如 onHide、onUnload 等,用于处理小程序在前台和后台的切换。
# 小程序的更新机制
小程序冷启动时如果发现有新版本,将会异步下载新版本的包,并同时会先用客户端本地的旧包进行启动,等下次冷启动才会应用上。如果需要马上应用最新版本,可以用 wx.getUpdateManager (opens new window) API 进行处理。
const updateManager = wx.getUpdateManager();
updateManager.onCheckForUpdate(function(res) {
// 请求完新版本信息的回调
console.log(res.hasUpdate);
});
updateManager.onUpdateReady(function() {
wx.showModal({
title: "更新提示",
content: "新版本已经准备好,是否重启应用?",
success(res) {
if (res.confirm) {
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
updateManager.applyUpdate();
}
}
});
});
updateManager.onUpdateFailed(function() {
// 新版本下载失败
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 小程序的数据通信机制
小程序是基于双线程的,那就意味着任何在视图层和逻辑层之间的数据传递都是线程间的通信,都会有一定的延时。这不像传统 Web 一样,当页面要更新时调用相关 API 就能同步渲染出来,在小程序架构里面,这一切成了异步操作。
异步会使得各部分的运行时序变得复杂一些。
比如在渲染首屏的时候,逻辑层与渲染层会同时开始初始化工作,但是渲染层需要有逻辑层的数据才能把界面渲染出来,如果渲染层初始化工作较快完成,就要等逻辑层的指令才能进行下一步工作。因此逻辑层与渲染层需要有一定的机制保证时序正确,在每个小程序页面的生命周期中,存在着若干次页面数据通信。
# 小程序的登录机制
调用 wx.login() (opens new window) 获取临时登录凭证 code,并回传到开发者服务器。
调用 auth.code2Session (opens new window) 接口,换取用户唯一标识 openid 、用户在微信开放平台帐号下的唯一标识 UnionID(若当前小程序已绑定到微信开放平台帐号)和会话密钥 session_key。
UnionID 机制
把小程序绑定到微信开放平台账号 (opens new window)后,可与该帐号下绑定的的其他移动应用、网站应用及公众号打通。
比如,同个用户在 PC 端的扫描登录、微信公众号开发的页面授权登录、微信小程序授权登录,这些场景中都能识别出是同一个用户,获取到的 UnionID 都是相同的。
# 小程序的性能问题
setData (opens new window) 是小程序开发中使用最频繁也是最容易出性能问题的接口。
setData 有以下限制:
单次设置的数据不能超过 1024kB,请尽量避免一次设置过多的数据。
每秒调用 setData 的次数不超过 20 次。
# 小程序的同层渲染
小程序的内容大多是渲染在 WebView 上的,如果把 WebView 看成单独的一层,那么由系统自带的这些原生组件则位于另一个更高的层级。两个层级是完全独立的,因此无法简单地通过使用 z-index 控制原生组件和非原生组件之间的相对层级。
为了解决这个问题,得通过一定的技术手段把原生组件直接渲染到 WebView 层级上。
为了解决原生组件层级最高的限制。小程序专门提供了 cover-view (opens new window) 和 cover-image (opens new window) 组件,可以覆盖在部分原生组件上面。这两个组件也是原生组件,但是使用限制与其他原生组件有所不同。
目前原生组件 (opens new window)均已支持同层渲染。
# Taro 多端打包编译原理
多端适配性:Taro 提供了一套统一的组件和 API,使得开发者可以在编写代码时使用统一的接口,而不需要为每个平台分别编写不同的代码。这样可以大大简化跨平台开发的难度。
编译器:Taro 的编译器是核心工具之一,负责将开发者编写的跨平台代码转换成特定平台的代码。在编译过程中,Taro 会根据目标平台生成对应的代码,以确保在不同平台上的执行兼容性。
多端组件库:Taro 提供了一套多端兼容的组件库,包括 View、Text、Image 等基础组件,以及一些平台差异的组件(例如在小程序中常见的 Button、Checkbox 等)。这样,开发者可以使用这些组件来构建跨平台应用。
条件编译:Taro 支持条件编译,可以通过在代码中使用条件判断语句,根据目标平台来执行不同的代码块。这使得开发者可以在需要时进行平台特定的适配。
插件体系:Taro 提供了插件体系,允许开发者根据需要扩展 Taro 的功能。通过插件,可以实现一些定制化的需求,以及对特定平台的适配。
在具体的打包过程中,Taro 的编译器会根据配置文件中的设置,将源代码编译成特定平台的可执行代码。
# 云开发
# 云开发简介
云开发 (opens new window) 是集成于小程序控制台的原生 serverless 云服务。核心功能包括:云函数、云数据库和云存储。
云函数:云函数是一段运行在云端的代码,无需管理服务器,在开发工具内编写、一键上传部署即可运行后端代码。云函数的运行机制 (opens new window)
云数据库:云开发提供了一个 JSON 数据库,顾名思义,数据库中的每条记录都是一个 JSON 格式的对象。一个数据库可以有多个集合(相当于关系型数据中的表),集合可看做一个 JSON 数组,数组中的每个对象就是一条记录,记录的格式是 JSON 对象。
云存储:云开发提供了一块存储空间,提供了上传文件到云端、带权限管理的云端下载能力,开发者可以在小程序端和云函数端通过 API 使用云存储功能。
# 云开发优势
微信 sdk 基本兼容云调用。
小程序上线域名只能是 https 且必须经过 ICP 备案,云开发可以不依托外部云服务器,这样项目就可以快速上线。
基础版免费使用,个人项目。
云调用可以直接获取 OpenID、AppID、UnionID。
云函数天然优势,不需要 access_token,直接改变用户登录方式(以及使用方式)。
开发效率提升,如果是对小程序进行扩展开发(原来就有项目)不需要修改接口,云函数帮你搞定原接口的兼容。
前端可以自己进行自己的服务端操作。
← jQuery 源码解析 移动端调试神器 →