资讯专栏INFORMATION COLUMN

小程序生命周期——小程序探索

Caizhenhao / 2709人阅读

摘要:运行机制小程序启动会有两种情况,一种是冷启动,一种是热启动。建议小程序在必要时使用监听内存告警事件,进行必要的内存清理。

前言
以小程序为切入点,深入理解总结方方面面的知识点,做成系列文章,希望能得到大神的指点和帮助新人入门,承上启下才是好程序猿
由于是系列第一篇文章,紧跟着的是一大段废话,只关心技术的可以跳过

转眼半年又要过去了,意味着来新公司快半年了,离上次写文章也半年了,浑浑噩噩得当码农半年了,这半年主要是搬砖(定制VUE和小程序)各种重复做功,说实话没太大长进,核心功能公司模板有了,大bug改不动,小bug改不完,大差不差交工就行,当然这是我自己的选择,自己XXX含着泪也要XX,自行脑补

大家应该都知道有一种公司叫做外包公司,利弊网上一大堆,关键看你怎么选择了

我现在就在外包公司,当初的打算就是用工作量来提高熟练度,也确实达成了“目标”,半年前,对于vue和小程序,也就是mvvm,只是理论层面,实际做项目还是有点怵,现在嘛结合上面的吐槽,前面的目标只能说达成了50%,毕竟做定制不管黑猫白猫,抓到老鼠就是好猫,遇到问题也是见招拆招,性能?迭代?可复用性?冗余?这些和我有关系吗?

针对上面这种情况,也就出现了很多人生导师的呐喊——待在外包不能超过半年,不然你就废了!!!(拿来鞭策自己)

现在我们公司已经准备向产品转型了,我也从定制部门转到了小程序产品部门,正好深入理解一波,和公司共同成长

感觉知识也是金字塔状的,刚开始我们在顶端,越往下拓展的就越多,我发现每当我想深入理解一个方面,必然引出更多关联知识,那怎么办呢,好记性不如烂笔头,在这年末年初之际,先给2019年开个好头

小程序App生命周期

小程序App生命周期是在app.js里面调用的,App(Object)函数用来注册一个小程序,接受一个 Object 参数,指定其小程序的生命周期回调

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

以上应该一眼就能看明白,以下主要讲讲前台、后台定义和运行机制等

1 . 前台、后台定义

当用户点击左上角关闭,或者按了设备 Home 键离开微信,小程序并没有直接销毁,而是进入了后台onHide;当再次进入微信或再次打开小程序,又会从后台进入前台onShow。需要注意的是:只有当小程序进入后台一定时间,或者系统资源占用过高,才会被真正的销毁。

2 . 运行机制

小程序启动会有两种情况,一种是「冷启动」,一种是「热启动」。 假如用户已经打开过某小程序,然后在一定时间内再次打开该小程序,此时无需重新启动,只需将后台态的小程序切换到前台onShow,这个过程就是热启动;冷启动指的是用户首次打开或小程序被微信主动销毁后再次打开的情况,此时小程序需要重新加载启动onLauch

小程序没有重启的概念

当小程序进入后台,客户端会维持一段时间的运行状态,超过一定时间后(目前是5分钟)会被微信主动销毁

在 iOS 上,当微信客户端在一定时间间隔内(目前是 5 秒)连续收到两次及以上系统内存告警时,会主动进行小程序的销毁,并提示用户 「该小程序可能导致微信响应变慢被终止」。建议小程序在必要时使用 wx.onMemoryWarning 监听内存告警事件,进行必要的内存清理。

3 . 更新机制

小程序冷启动时如果发现有新版本,将会异步下载新版本的代码包,并同时用客户端本地的包进行启动,即新版本的小程序需要等下一次冷启动才会应用上。 如果需要马上应用最新版本,可以使用 wx.getUpdateManager API 进行处理

小程序强制更新

//注意,小程序的更新的api需要基础库在1.9.90以上
const updateManager = wx.getUpdateManager()
updateManager.onCheckForUpdate(function (res) {
    // 请求完新版本信息的回调,省略回调会报错,如下图
    console.log(res.hasUpdate)
})
updateManager.onUpdateReady(function () {
    wx.showModal({
        title: "更新提示",
        content: "新版本已经准备好,是否重启应用?",
        success: function (res) {
            if (res.confirm) {
                // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
                updateManager.applyUpdate()
            }
        }
    })
})
updateManager.onUpdateFailed(function () {
    // 新的版本下载失败
    wx.showModal({
        title: "更新提示",
        content: "新版本下载失败",
        showCancel:false
    })
})

3 . 再次打开逻辑

用户打开小程序的预期有以下两类场景:1、打开首页 2、打开指定页面

现在要打开的是首页,如果上一次退出的时候是首页,则保留状态;否则,清空原来的页面栈,打开首页(相当于执行 wx.reLaunch 到首页)

现在要打开的是指定页面,不管上次在什么页面,清空原来的页面栈,打开指定页面(相当于执行 wx.reLaunch 到指定页)

小程序Page生命周期

Page(Object) 函数用来注册一个页面。接受一个 Object 类型参数,其指定页面的初始数据、生命周期回调、事件处理函数等

引用一张不错的图片来让你一目了然,图片来源于网络

补充:app.onPageNotFound(Object)
基础库 1.9.90 开始支持,低版本需做兼容处理。

小程序要打开的页面不存在时触发,也可以使用 wx.onPageNotFound 绑定监听

开发者可以在回调中进行页面重定向,但必须在回调中同步处理,异步处理(例如 setTimeout 异步执行)无效

主要用于轮播、魔方等动态指定跳转页面的场景,避免出现页面不存在的情况

App({
  onPageNotFound(res) {
    // 可以封装一个小程序跳转函数,智能解决tabbar页面跳转的问题
    wx.redirectTo({
      url: "pages/..."
    })
  }
})
生命周期执行顺序
生命周期执行顺序
分别了解了App和Page的生命周期函数,那他们之间有何关联

吐槽一句,好多文章说什么app的生命周期函数onLauch可能会在page的onLoad之后触发,搞得我一脸懵逼,说话这么不严谨,真的好吗???

先看看正常的生命周期
App({
  onLaunch() {
     console.log("app---onLaunch");
  }, 
  onShow() {
    console.log("app---onShow");
  },
  onHide() {
    console.log("app---onHide");
  }
})

Page({

  onLoad(options) {
    console.log("page---onLoad");
  },

  onReady() {
    console.log("page---onReady");
  },

  onShow() {
    console.log("page---onShow");
  },

  onHide() {
    console.log("page---onHide");
  },

  onUnload() {
    console.log("page---onUnload");
  }

})
控制台输出

应该说永远是这个顺序,现在再加点代码,就用官方的例子
App({
  onLaunch() {
     console.log("app---onLaunch");
      // 获取用户信息
    wx.getSetting({
      success: res => {
        if (res.authSetting["scope.userInfo"]) {
          // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
          wx.getUserInfo({
            success: res => {
              // 可以将 res 发送给后台解码出 unionId
              this.globalData.userInfo = res.userInfo
              console.log("app---onLaunch---success");
              // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
              // 所以此处加入 callback 以防止这种情况
              if (this.userInfoReadyCallback) {
                this.userInfoReadyCallback(res)
              }
            }
          })
        }
      }
    })
  }
})

Page({
  onLoad(options) {
    console.log("page---onLoad");
    if (app.globalData.userInfo) {
      this.setData({
        userInfo: app.globalData.userInfo,
        hasUserInfo: true
      })
    } else if (this.data.canIUse) {
      // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
      // 所以此处加入 callback 以防止这种情况
      app.userInfoReadyCallback = res => {
        this.setData({
          userInfo: res.userInfo,
          hasUserInfo: true
        })
      }
    } else {
      // 在没有 open-type=getUserInfo 版本的兼容处理
      wx.getUserInfo({
        success: res => {
          app.globalData.userInfo = res.userInfo
          this.setData({
            userInfo: res.userInfo,
            hasUserInfo: true
          })
        }
      })
    }
  }
})
控制台输出

可以看出小程序生命周期函数并没有错乱,只是加了异步操作

你永远不知道异步操作会排在正常周期的哪一个位置

解决方案
例子中已经给出了callback的方案,现在也可以使用promise来解决

1 . callback

解释一波:Page页面判断当前app.globalData.userInfo是否有值

如果有,说明异步操作很顺利,当做同步往下操作即可

如果没有,则定义一个app方法(回调函数)app.userInfoReadyCallback = res => {...}

因为Page.onLoad没有顺利拿到app.globalData.userInfo,说明App页面请求success异步操作滞后了

此时APP页面不仅会给globalData.userInfo赋值,还会执行Page页面定义的回调方法,完成业务逻辑

以上例子是官方对于授权之后的操作流程示例,实际使用替换自己的初始化函数和业务逻辑

注意事项
app.onLaunch全局只触发一次,也就是打开的第一个页面会有异步问题,打开第二个页面肯定是可以拿到初始化数据的,但是小程序可以从不同场景进入,可能打开的并非是首页,这时就需要给每一个可能被第一次就打开的页面,写回调函数,暂时没想到类似vue那种设置全局路由回调的方案

2 . promise

最终效果应该和回调一样,之前小程序不支持promise,一直没有好好用过,等以后多带带研究~

Page实例生命周期
先来看一张很熟悉的图
官方原话(以下内容你不需要立马完全弄明白,不过以后它会有帮助)

咋一看,什么鬼,好吧~我听你的,以后再说~

转眼间,以后就到啦!好在有大佬解释过了,借花献佛,谁让我是搬运工呢(最后会贴上参考文章链接)

Page实例由两大线程组成

负责界面的线程(view thread)和服务线程(appservice thread),各司其职又互相配合

界面线程有四大状态:

初始化状态:初始化界面线程所需要的工作,包括工作机制,基本和我们开发者没有关系,等初始化完毕就向 “服务线程”发送初始化完毕信号,然后进入等待传回初始化数据状态

首次渲染状态:收到“服务线程”发来的初始化数据后(就是 json和js中的data数据),就开始渲染小程序界面,渲染完毕后,发送“首次渲染完毕信号”给服务线程,并将页面展示给用户

持续渲染状态:此时界面线程继续一直等待“服务线程”通过this.setdata()函数发送来的界面数据,只要收到就重新局部渲染,也因此只要更新数据并发送信号,界面就自动更新

结束状态:你懂得

服务线程五大状态:

初始化状态:无需和其他模块交流,跟小程序开发也没多大关联,此阶段就是启动服务线程所需的基本功能,比如信号发送模块。系统的初始化工作完毕,就调用自定义的onload和onshow,

然后等待界面线程的“界面线程初始化完成”信号。
onload是只会首次渲染的时候执行一次,onshow是每次界面切换都会执行,简单理解,这就是唯一差别

等待激活状态:接收到“界面线程初始化完成”信号后,将初始化数据发送给“界面线程”,等待界面线程完成初次渲染

激活状态:收到界面线程发送来的“首次渲染完成”信号后,就进入激活状态既程序的正常运行状态,并调用自定义的onReady()函数。

此状态下就可以通过 this.setData 函数发送界面数据给界面线程进行局部渲染,更新页面

后台运行状态:如果界面进入后台,服务线程就进入后台运行状态,从目前的官方解读来说,这个状态挺奇怪的,和激活状态是相同的,也可以通过setdata函数更新界面的

总结一下 小程序的一生

打开小程序 -> app.onLaunch -> app.onShow -> Page.onLoad -> Page.onShow -> Page.onReady

进入下一个页面 -> Page.onHide -> Next.onLoad -> Next.onShow -> Next.onReady

返回上一个页面 -> Next.onUnload -> Page.onShow

离开小程序 -> app.onHide

再次进入 -> app未销毁 ->app.onShow 否则从头开始(销毁判断看上文运行机制)

注意:Tabbar页面初始化之后不会被销毁,也就是只会执行一次 onLoad 函数

只触发一次的,一般都是用来初始化操作

onLaunch:初始化全局数据,注意异步问题

onLoad:初始化页面数据

onReady:代表页面已经准备妥当,界面内容的修改,最好放在这里,如wx.setNavigationBarTitle

onUnload:清除定时器,因为所有页面的脚本逻辑都跑在同一个JsCore线程

触发多次的,一般用来改变状态

onShow:刷新

onHide:重置

参考文献
http://www.wxapp-union.com/ar...
http://www.wxapp-union.com/ar...
https://developers.weixin.qq....

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/100727.html

相关文章

  • 深入理解程序中的数据——程序探索

    摘要:传输时间与数据量大体上呈现正相关关系,传输过大的数据将使这一时间显著增加。小程序不管从组件化开发调试发布灰度回滚上报统计监控和最近的云能力都非常完善,小程序的工程化简直就是前端的典范。 研究背景 上一篇文章了解了小程序的生命周期,接下来研究一下数据通信,我觉得清楚了生命周期和数据通信,就能对整个程序有一定的把控能力,定位问题和解决问题的能力将大幅提高我刚开始撸小程序的时候,觉得看看文...

    Jochen 评论0 收藏0
  • 从入门到上线一个天气程序

    摘要:天气预报小程序说了很多小程序开发的基础准备,下面就结合个人实际练手项目天气预报小程序简单说明。物料准备从需求结果导向,天气程序首先要能获取到当前所在地天气状况,再次可以自由选择某地,知道其天气状况。 前言 学习了一段时间小程序,大致过了两遍开发文档,抽空做个自己的天气预报小程序,全当是练手,在这记录下。小程序开发的安装、注册和接入等流程就不罗列了,在小程序接入指南已经写得很清楚了,以下...

    Anshiii 评论0 收藏0
  • Taro 简介

    摘要:让人又爱又恨的微信小程序自微信小程序以下简称小程序诞生以来,就伴随着赞誉与争议不断。同时于开发者来说,小程序的生态不断在完善,许多的坑已被踩平,虽然还是存在一些令人诟病的问题,但已经足见微信的诚意了。 Taro 介绍 在互联网不断发展的今天,前端程序员们也不断面临着新的挑战,在这个变化多端、不断革新自己的领域,每一年都有新的美好事物在发生。从去年微信小程序的诞生,到今年的逐渐火热,以及...

    sixgo 评论0 收藏0
  • 微信程序开发中的二三事之网易云信IMSDK DEMO

    摘要:传统的网页编程采用的三剑客来实现,在微信小程序中同样有三剑客。观察者模式不难实现,重点是如何在微信小程序中搭配其特有的生命周期来使用。交互事件传统的事件传递类型有冒泡型与捕获型,微信小程序中自然也有。 本文由作者邹永胜授权网易云社区发布。 简介为了更好的展示我们即时通讯SDK强悍的能力,网易云信IM SDK微信小程序DEMO的开发就提上了日程。用产品的话说就是: 云信 IM 小程序 S...

    weij 评论0 收藏0
  • 微信程序Taro开发(2):生命周期及开发中注意点

    摘要:入口文件继承自组件基类,它同样拥有组件生命周期,但因为入口文件的特殊性,他的生命周期并不完整,如。支持组件化开发,组件代码可以放在任意位置,不过建议放在下的目录中。 生命周期 componentWillMount 在微信小程序中这一生命周期方法对应页面的onLoad或入口文件app中的onLaunch componentDidMount 在微信小程序中这一生命周期方法对应页面的onRe...

    morgan 评论0 收藏0

发表评论

0条评论

Caizhenhao

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<