27
小程序的运行环境
微信小程序运行在多种平台上:iOS/iPadOS 微信客户端、Android 微信客户端、Windows PC 微信客户端、Mac 微信客户端、小程序硬件框架和用于调试的微信开发者工具等。
不同运行环境下,脚本执行环境以及用于组件渲染的环境是不同的,性能表现也存在差异:
- 在 iOS、iPadOS 和 Mac OS 上,小程序逻辑层的 JavaScript 代码运行在 JavaScriptCore 中,视图层是由 WKWebView 来渲染的,环境有 iOS 14、iPad OS 14、Mac OS 11.4 等;
- 在 Android 上,小程序逻辑层的 JavaScript 代码运行在 V8 中,视图层是由基于 Mobile Chromium 内核的微信自研 XWeb 引擎来渲染的;
- 在 Windows 上,小程序逻辑层 JavaScript 和视图层都是用 Chromium 内核;
- 在 开发工具上,小程序逻辑层的 JavaScript 代码是运行在 NW.js 中,视图层是由 Chromium Webview 来渲染的。
JavaScriptCore 无法开启 JIT 编译 (Just-In-Time Compiler),同等条件下的运行性能要明显低于其他平台。
平台差异
尽管各运行环境是十分相似的,但是还是有些许区别:
-
JavaScript语法和 API 支持不一致:语法上开发者可以通过开启ES6转ES5的功能来规避(详情);此外,小程序基础库内置了必要的Polyfill,来弥补API的差异(详情)。 -
WXSS渲染表现不一致:尽管可以通过开启样式补全来规避大部分的问题,还是建议开发者需要在各端分别检查小程序的真实表现。
开发者工具仅供调试使用,最终的表现以客户端为准。
**
**
JavaScript 支持情况
运行限制
基于安全考虑,小程序中不支持动态执行 JS 代码,即:
- 不支持使用
eval执行 JS 代码 - 不支持使用
new Function创建函数
-
new Function('return this')除外
标准 ECMAScript 支持
小程序的 JS 执行环境 在不同平台上的执行环境存在差异,因此导致不同平台对 ECMAScript 标准的支持存在差异。
小程序基础库为了尽量抹平这些差异,内置了一份 core-js Polyfill。core-js 可以将平台环境缺失的标准 API 补齐。
需要注意的是,平台对 ECMAScript 语法的支持差异无法抹平,当你需要使用一些高级语法时,如 async/await 时,则需要借助 代码转换工具 来支持这些语法。
无法被 Polyfill 的 API
以下 API 在部分低版本客户端中无法使用,请注意尽量避免使用
Proxy对象
与标准的差异
Promise 时序差异
由于实现原因与 iOS JavaScriptCore 限制,iOS 环境下的 Promise 是一个使用 setTimeout 模拟的 Polyfill。这意味着 Promise 触发的任务为普通任务,而非微任务,进而导致 在 iOS 下的 Promise 时序会和标准存在差异。
var arr = []
setTimeout(() => arr.push(6), 0)
arr.push(1)
const p = new Promise(resolve => {
arr.push(2)
resolve()
})
arr.push(3)
p.then(() => arr.push(5))
arr.push(4)
setTimeout(() => arr.push(7), 0)
setTimeout(() => {
// 应该输出 [1,2,3,4,5,6,7]
// 在 iOS 小程序环境,这里会输出 [1,2,3,4,6,5,7]
console.log(arr)
}, 1000)
关于普通任务和微任务的区别可以查看这篇文章
如何判断当前环境需要哪些 Polyfill & 代码转换目标
特定的小程序基础库版本有最低微信客户端版本要求,如基础库 v2.15.0 要求安卓最低版本 7.0.22,iOS 最低版本 7.0.20。
而特定的客户端版本有最低操作系统版本要求,如 iOS 7.0.20 要求最低 iOS 10。
从而,当指定特定小程序基础库版本时(可以在 小程序管理页 【设置】-【基本设置】-【基础库最低版本设置】中设置),我们能够得到最低需要支持的执行环境。
具体数据可以从 这个开源库 中获得。
小程序运行机制
1. 小程序的生命周期
小程序从启动到最终被销毁,会经历很多不同的状态,小程序在不同状态下会有不同的表现。
1.1 小程序启动
从用户认知的角度看,广义的小程序启动可以分为两种情况,一种是冷启动,一种是热启动。
- 冷启动:如果用户首次打开,或小程序销毁后被用户再次打开,此时小程序需要重新加载启动,即冷启动。
- 热启动:如果用户已经打开过某小程序,然后在一定时间内再次打开该小程序,此时小程序并未被销毁,只是从后台状态进入前台状态,这个过程就是热启动。
从小程序生命周期的角度来看,我们一般讲的「启动」专指冷启动,热启动一般被称为后台切前台。
1.2 前台与后台
小程序启动后,界面被展示给用户,此时小程序处于「前台」状态。
当用户「关闭」小程序时,小程序并没有真正被关闭,而是进入了「后台」状态,此时小程序还可以短暂运行一小段时间,但部分 API 的使用会受到限制。切后台的方式包括但不限于以下几种:
- 点击右上角胶囊按钮离开小程序
- iOS 从屏幕左侧右滑离开小程序
- 安卓点击返回键离开小程序
- 小程序前台运行时直接把微信切后台(手势或 Home 键)
- 小程序前台运行时直接锁屏
当用户再次进入微信并打开小程序,小程序又会重新进入「前台」状态。
1.3 挂起
小程序进入「后台」状态一段时间后(目前是 5 秒),微信会停止小程序 JS 线程的执行,小程序进入「挂起」状态。此时小程序的内存状态会被保留,但开发者代码执行会停止,事件和接口回调会在小程序再次进入「前台」时触发。
当开发者使用了后台音乐播放、后台地理位置等能力时,小程序可以在「后台」持续运行,不会进入到「挂起」状态
1.4 小程序销毁
如果用户很久没有使用小程序,或者系统资源紧张,小程序会被「销毁」,即完全终止运行。具体而言包括以下几种情形:
- 当小程序进入后台并被「挂起」后,如果很长时间(目前是 30 分钟)都未再次进入前台,小程序会被销毁。
- 当小程序占用系统资源过高,可能会被系统销毁或被微信客户端主动回收。
-
- 在 iOS 上,当微信客户端在一定时间间隔内连续收到系统内存告警时,会根据一定的策略,主动销毁小程序,并提示用户 「运行内存不足,请重新打开该小程序」。具体策略会持续进行调整优化。
- 建议小程序在必要时使用 wx.onMemoryWarning 监听内存告警事件,进行必要的内存清理。
基础库 1.1.0 及以上,1.4.0 以下版本: 当用户从扫一扫、转发等入口(场景值为1007, 1008, 1011, 1025)进入小程序,且没有置顶小程序的情况下退出,小程序会被销毁。
2. 小程序冷启动的页面
小程序冷启动时,打开的页面有以下情况
- (A 类场景)若启动的场景中不带 path
-
- 基础库 2.8.0 以下版本,进入首页
- 基础库 2.8.0 及以上版本遵循「重新启动策略」,可能是首页或上次退出的页面
- (B 类场景)若启动的场景中带有 path,则启动进入对应 path 的页面
2.1 重新启动策略
基础库 2.8.0 开始支持,低版本需做兼容处理。
小程序冷启动时,如果启动时不带 path(A 类场景),默认情况下将会进入小程序的首页。 在页面对应的 json 文件中(也可以全局配置在 app.json 的 window 段中),指定 restartStrategy 配置项可以改变这个默认的行为,使得从某个页面退出后,下次 A 类场景的冷启动可以回到这个页面。
代码示例:
{
"restartStrategy": "homePage"
}
restartStrategy 可选值:
| 可选值 | 含义 |
|---|---|
| homePage | (默认值)如果从这个页面退出小程序,下次将从首页冷启动 |
| homePageAndLatestPage | 如果从这个页面退出小程序,下次冷启动后立刻加载这个页面,页面的参数保持不变(不可用于 tab 页) |
注意:即使不配置为 homePage ,小程序如果退出过久(当前默认一天时间,可以使用退出状态来调整),下次冷启动时也将不再遵循 restartStrategy 的配置,而是直接从首页冷启动。
无论如何,页面中的状态并不会被保留,如输入框中的文本内容、 checkbox 的勾选状态等都不会还原。如果需要还原或部分还原,需要利用退出状态。