小程序学习笔记-启动

小程序启动过程

初次进入小程序的时候,微信客户端初始化好宿主环境,同时从网络下载或者从本地缓存中拿到小程序的代码包,把它注入到宿主环境。大概是这么个过程:

  1. 创建线程(渲染层和逻辑层),启动小程序。
  2. 载入基础库(WebView 基础库和 AppService 基础库)。
  3. 载入小程序业务代码(下载或者从本地缓存中拿到)。
  4. 使用App()注册程序实例。

为了让小程序业务代码能够调用 API 以及组件,就需要在启动小程序后先载入基础库,接着再载入业务代码。
由于所有小程序都需要注入相同的基础库,所以小程序的基础库会被提前内置在微信客户端。而基础库是热更新的,故一般等微信客户端携带上一个稳定版的基础库正式发布后,再进行新版本基础库的灰度和推送。

注册 App 实例

宿主环境提供了App()构造器用来注册一个程序 App。App 实例是单例对象,在其他 JS 脚本中可以使用宿主环境提供的getApp()来获取程序实例。

App() 必须在 app.js 中调用,必须调用且只能调用一次。不然会出现无法预期的后果。

App()函数用来注册一个小程序。接受一个Object参数,其指定小程序的生命周期回调等。

onLaunch
小程序初始化完成时(全局只触发一次)触发onLaunch回调。
在微信客户端中打开小程序有很多途径,对不同途径的打开方式,小程序有时需要做不同的业务处理。所以微信客户端会把打开方式带给onLaunchonShow的调用参数options,我们可以根据参数来判断一些进入方式,以及做对应的逻辑处理。

例如,我需要拿到从另外一个小程序跳转过来携带的信息,此时场景值应该是1037(参考场景值):

App({
  // ...
  onShow: function(e) {
    if(e.scene === 1037){
      const data = e.referrerInfo && e.referrerInfo.extraData; // 拿到对应的数据
      const refAppid = e.referrerInfo && e.referrerInfo.appId; // 拿到对应的小程序appid
    }
  }
})

onShow
小程序启动,或从后台进入前台显示时触发onShow回调。通常我们用来处理数据和状态的更新。
小程序进入后台状态:当用户点击左上角关闭,或者按了设备 Home 键离开微信,小程序并没有直接销毁。

onHide
小程序从前台进入后台时触发onHide回调。
小程序进入前台状态:当再次进入微信或再次打开小程序,又会从后台进入前台。

获取 App 实例

我们可以使用全局的getApp()函数来获取到小程序 App 实例(在App()内的函数中使用this就可以拿到app实例。)。

前面我们可以看到,App 的生命周期是由微信客户端根据用户操作主动触发的。故我们通过getApp()获取实例之后,不应该私自调用生命周期函数。

具体的原理是什么呢?小程序的 JS 脚本是运行在 JsCore 的线程里,小程序的每个页面各自有一个 WebView 线程进行渲染,所以小程序切换页面时,小程序逻辑层的 JS 脚本运行上下文依旧在同一个 JsCore 线程中。

因此,App 构造器可以传递其他参数作为全局属性以达到全局共享数据的目的。

由于所有页面的脚本逻辑都跑在同一个 JsCore 线程,页面使用setTimeout或者setInterval的定时器,即使切换了页面,也需要自行清理定时器。可以选择:

  • 在页面离开onUnloadonHide等的时候自行清理
  • 做全局的定时器管理(当然也还是需要关闭时清理)

说到页面之间的数据共享,我们也该来讲讲小程序里页面的启动。

小程序页面


页面生命周期

宿主环境提供了Page(Object)构造器用来注册一个小程序页面,接受一个Object类型参数,其指定页面的初始数据、生命周期回调、事件处理函数等。

注意:Object 内容在页面加载时会进行一次深拷贝,需考虑数据大小对页面加载的开销。

这里我们先来看看官方的生命周期图:

image

左侧是渲染层,右侧是逻辑层。几件事:

  1. 渲染层和逻辑层之间通信,是通过 Native 转发实现的。
  2. 逻辑层通过 Page 实例的setData方法传递数据到渲染层。由于需要两个线程的一些通信消耗,为了提高性能,每次只设置需要改变的最小单位数据。
  3. 生命周期顺序:onLoad -> onShow -> onReady

页面生命周期函数
onLoad(Object query)
页面加载时触发。一个页面只会调用一次,可以在onLoad的参数中获取打开当前页面路径中的参数。

onShow()
页面显示/切入前台时触发。

onReady()
页面初次渲染完成时触发。一个页面只会调用一次,代表页面已经准备妥当,可以和视图层进行交互。

onHide()
页面隐藏/切入后台时触发。

onUnload()
页面卸载时触发。

和小程序实例的生命周期对比,其实页面也是有些相似。这里需要注意几点:

  • 当前页面路径的参数获取,只能在onLoad(query)query参数中获取,无法在onShow()中获取
  • onLoadonReadyonUnload,一个页面都只会调用一次
  • 页面是卸载还是切换到后台,这些除了与小程序的后台切换有关系,还会与页面的跳转、切换逻辑有关系

下面我们就来看下页面的逻辑。

页面导航

我们知道,一个小程序会拥有多个页面。在小程序里会有页面的层级关系,例如通过wx.navigateTo推入一个新的页面,在首页使用2次wx.navigateTo后,页面层级会有三层:

image

获取页面栈
getCurrentPages()函数用于获取当前页面栈的实例,以数组形式按栈的顺序给出,第一个元素为首页,最后一个元素为当前页面。
需要注意的是:

  • 修改页面栈会导致路由以及页面状态错误
  • App.onLaunch的时候 page 还没有生成,不能在这调用getCurrentPages()

但是其实不是每一次切换页面,都会被记录到页面栈里,我们看看页面导航的一些方法和行为:

路由方式 触发时机 页面栈表现 进入方式
初始化 小程序打开的第一个页面 新页面入栈 从下往上升起
打开新页面 调用 API wx.navigateTo 新页面入栈 从右往左切入
页面重定向 调用 API wx.redirectTo 当前页面出栈,新页面入栈 页面重新加载
页面返回 返回/调用 API wx.navigateBack 页面不断出栈,直到目标返回页 从右往左切回
Tab 切换 切换/调用 API wx.switchTab 页面全部出栈,只留下新的 Tab 页面 页面重新加载
重加载 调用 API wx.reLaunch 页面全部出栈,只留下新的页面 页面重新加载

关于导航 API 的几个补充点:

  • wx.navigateTowx.redirectTo只能打开非 TabBar 页面,wx.switchTab只能打开 Tabbar 页面,wx.reLaunch可以打开任意页面
  • TabBar 页面指在 app.json 的 TabBar 字段定义的页面(客户端窗口的底部或顶部有 tab 栏可以切换页面)
  • 跳转到 TabBar 页面,路径后不能带参数(注意,Tabbar 页面初始化之后不会被销毁)
  • 调用页面路由带的参数可以在目标页面的onLoad中获取

页面层级准备

我们知道页面栈的表现,以及一些常见的导航方法,而小程序基础库也在页面层级做了些体验优化。

对于每一个新的页面层级,视图层都需要进行一些额外的准备工作:

  • 在小程序启动前,微信会提前准备好一个页面层级用于展示小程序的首页
  • 每当一个页面层级被用于渲染页面,微信都会提前开始准备一个新的页面层级,减少每次新开页面的耗时

每个页面的准备都有三个阶段:

  1. 启动一个 WebView。
  2. WebView 中初始化基础库(此时还会进行一些基础库内部优化,以提升页面渲染性能)。
  3. 注入小程序 WXML 结构和 WXSS 样式(小程序能在接收到页面初始数据之后马上开始渲染页面)。

PS:wx.redirectTo不会打开一个新的页面层级,而是将当前页面层级重新初始化。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容