微信小程序生命周期淺析

小程序生命周期

運(yùn)行機(jī)制

小程序什么時(shí)候會被銷毀
當(dāng)小程序進(jìn)入后臺茂装,客戶端會維持一段時(shí)間的運(yùn)行狀態(tài)宁否,超過一定時(shí)間后(目前是5分鐘)會被微信主動(dòng)銷毀副渴。
當(dāng)短時(shí)間內(nèi)(5s)連續(xù)收到兩次以上收到系統(tǒng)內(nèi)存告警翼悴,會進(jìn)行小程序的銷毀信卡。
再次打開邏輯
用戶打開小程序的預(yù)期有以下兩類場景:
  • A. 打開首頁:場景值有1001隔缀,1019,1022傍菇,1023蚕泽,1038,1056
  • B. 打開小程序指定的某個(gè)頁面:場景值為除A以外的其他

當(dāng)再次打開一個(gè)小程序邏輯如下:

上一次的場景 當(dāng)前打開的場景 效果
A A 保留原來的狀態(tài)
B A 清空原來的頁面棧桥嗤,打開首頁(相當(dāng)于執(zhí)行wx.reLaunch到首頁)
A或B B 清空原來的頁面棧须妻,打開指定頁面(相當(dāng)于執(zhí)行wx.reLaunch到指定頁

小程序的生命周期

App()函數(shù)注冊一個(gè)小程序。接受一個(gè)Object參數(shù)泛领,其指定小程序的生命周期回調(diào)等荒吏。這里的生命周期針對整個(gè)小程序項(xiàng)目,而不是哪個(gè)頁面渊鞋。
object參數(shù)說明:
前臺绰更、后臺定義: 當(dāng)用戶點(diǎn)擊左上角關(guān)閉,或者按了設(shè)備Home鍵離開微信锡宋,小程序并沒有直接銷毀儡湾,而是進(jìn)入了后臺;當(dāng)在此進(jìn)入微信或再次打開小程序执俩,又會從后臺進(jìn)入前臺徐钠。
下面是一個(gè)示例,代碼如下:
    //app.js
    App({
      onLaunch: function (options) {
        // 小程序初始化完成時(shí)觸發(fā)役首,全局只觸發(fā)一次尝丐。
        // options說明:
        // path:打開小程序的路徑
        // query 打開小程序的query
        // scene 打開小程序的場景值
        // shareTicket 轉(zhuǎn)發(fā)信息相關(guān)
        // referrerInfo 當(dāng)場景為由另一個(gè)小程序或公眾號或App打開時(shí),返回此字段
         console.log('app >> onLaunch 衡奥, options::',options);
      },
      onShow: function(options){
        // 小程序啟動(dòng)爹袁,或從后臺進(jìn)入前臺顯示時(shí)觸發(fā)
        // 參數(shù)與onLaunch一致
        console.log('app >> onShow值依, options :: ',options);
      },
      onHide:function(){
        //小程序從前臺進(jìn)入后臺時(shí)觸發(fā)晾剖。
        console.log('app >> onHide');
      },
      onError:function(error){
        // 小程序發(fā)生腳本錯(cuò)誤顽腾,或者api調(diào)用失敗時(shí)觸發(fā)蛾绎。
        // error String 錯(cuò)誤信息缤弦,包含堆棧信息
        console.log('app >> onError 年叮, error::'+error);
      },
      onPageNotFound(Object){
        // 基礎(chǔ)庫1.9.90開始支持
        // 小程序要打開的頁面不存在時(shí)觸發(fā)砂轻。
        // Object參數(shù)說明:
        // path String 不存在的頁面路徑
        // query object 打開不存在頁面的query
        // isEntryPage Boolean 是否本次啟動(dòng)的首個(gè)頁面
        console.log('app >> onPageNotFound , Object :: ',Object);
        //注:如果開發(fā)者沒有添加 onPageNotFound 監(jiān)聽胃珍,當(dāng)跳轉(zhuǎn)頁面不存在時(shí)辰晕,將推入微信客戶端原生的頁面不存在提示頁面蛤迎。
        // 如果 onPageNotFound 回調(diào)中又重定向到另一個(gè)不存在的頁面,將推入微信客戶端原生的頁面不存在提示頁面含友,并且不再回調(diào) onPageNotFound替裆。
      }
    })
當(dāng)啟動(dòng)小程序時(shí)校辩,在開發(fā)者工具中可以看到控制臺打印如下信息
app

頁面的生命周期

Page(Object)函數(shù)用來注冊一個(gè)頁面。接受一個(gè)Object類型參數(shù)辆童,其指定頁面的初始數(shù)據(jù)宜咒、生命周期回調(diào)、時(shí)間處理函數(shù)等把鉴。

下面用一個(gè)示例來嘗試下小程序的生命周期流程

該示例有4個(gè)頁面pageA/pageB/pageC/pageD故黑,其中pageA和pageB是兩個(gè)tab頁面,即通過底部標(biāo)簽切換的頁面庭砍。而pageC和pageD是兩個(gè)普通頁面场晶。示例頁面如下:
pageA
pageB
pageC
pageD
四個(gè)頁面如圖所示,有一些按鈕分別表示不同的路由跳轉(zhuǎn)方式怠缸。
下面是pageA相關(guān)的部分頁面代碼诗轻,其他頁面類似
    Page({
        data:{

        },
        onLoad:function(options){
            //頁面加載時(shí)觸發(fā)。一個(gè)頁面只會調(diào)用一次揭北,可以在onLoad的參數(shù)中獲取打開當(dāng)前路徑中的參數(shù)扳炬。
            //參數(shù) options Object 打開當(dāng)前頁面路徑中的參數(shù)
            console.log('pageA >> onLoad , options ::',options);
        },
        onReady:function(){
            //頁面初次渲染完成時(shí)觸發(fā)。一個(gè)頁面只會調(diào)用一次搔体,代表頁面已經(jīng)準(zhǔn)備妥當(dāng)恨樟,可以和視圖層進(jìn)行交互。
            console.log('pageA >> onReady');
        },
        onShow:function(){
            //頁面顯示/切入前臺時(shí)觸發(fā)
            console.log('pageA >> onShow');
        },
        onHide:function(){
            //頁面隱藏/切入后臺時(shí)觸發(fā)疚俱。
            console.log('pageA >> onHide');
        },
        onUnload:function(){
            //頁面卸載時(shí)觸發(fā)劝术。
            console.log('pageA >> onUnload');
        },
        // 自定義方法
        navigateToC:function(){
            //保留當(dāng)前頁面,跳轉(zhuǎn)到應(yīng)用內(nèi)的某個(gè)頁面计螺,但是不能跳到 tabbar 頁面夯尽。使用 wx.navigateBack 可以返回到原頁面。
            console.log('%cpageA==========navigateToC===========','color:red');
            wx.navigateTo({
                url:'/pages/page-c/index'
            });
        },
        redirectToC:function(){
            //關(guān)閉當(dāng)前頁面登馒,跳轉(zhuǎn)到應(yīng)用內(nèi)的某個(gè)頁面,但是不允許跳轉(zhuǎn)到tabbar頁面
            console.log('%cpageA==========redirectToC===========','color:red');
            wx.redirectTo({
                url:'/pages/page-c/index'
            });
        },
        reLaunchToC:function(){
            //關(guān)閉所有頁面咆槽,打開到應(yīng)用內(nèi)的某個(gè)頁面
            console.log('%cpageA==========reLaunchToC===========','color:red');
            wx.reLaunch({
                url:'/pages/page-c/index'
            })
        }
    });


下面是各種情況下的試驗(yàn)結(jié)果:

當(dāng)前頁面 路由后頁面 跳轉(zhuǎn)方式 觸發(fā)的生命周期(按順序) 說明
A A 首次打開
first
執(zhí)行小程序的onlaunch>onShow陈轿,然后執(zhí)行頁面的onLoad>onShow>onReady
A B 點(diǎn)擊tab標(biāo)簽
AtoB
pageA隱藏,pageB加載
A B(再次打開) 點(diǎn)擊tab標(biāo)簽
AtoB2
pageA隱藏秦忿,pageB顯示
A C navigateTo
An2C
pageA隱藏麦射,pageC加載
A C redirectTo
Ar2C
pageA卸載,pageC加載
A C reLaunchTo
AL2c
卸載所有頁面灯谣,pageC加載
C A switchTabTo
Cs2A
卸載所有非tab頁面潜秋,pageA顯示
D C navigateBack
Db2C
pageD卸載,pageC顯示
D B switchTabTo
Ds2B
卸載所有非tab頁面胎许,pageC顯示,pageA任然存在
D 關(guān)閉小程序
image.png
打開A/B/C/D峻呛,從pageD關(guān)閉小程序罗售,可以看到執(zhí)行的D和App的onHide,小程序并沒有真正退出
上面說到的情況都較為簡單的流程钩述,從官方文檔便可以理解到寨躁,下面試驗(yàn)一些復(fù)雜的流程。
第一種 A->C->D-B牙勘,其實(shí)這個(gè)過程按正常思維便可以理解职恳,下圖為整個(gè)過程的展示:
ACDB
上面的圖片展示了小程序從打開到走完這個(gè)流程的所有生命周期,其余都好理解方面,值得注意的是放钦,DswitchTabToB的時(shí)候,會干掉所有其他非tabBar頁面恭金,所以pageC和pageD都會觸發(fā)onUnload
第二種 A->C->C->C最筒,這種情況下我們從C頁面繼續(xù)跳轉(zhuǎn)到C頁面,為了看下小程序是新創(chuàng)建一個(gè)C頁面蔚叨,還是復(fù)用之前的C頁面床蜘,我們在C頁面中加一個(gè)input用來識別頁面是否被復(fù)用。試驗(yàn)結(jié)果如下圖:
ACCC
事實(shí)證明每次我們都打開了一個(gè)新的頁面蔑水,我們的輸入框是空白的邢锯,而我每次分別輸入了1/2/3,從生命周期函數(shù)也可以看到每次C都執(zhí)行了onHide但沒有執(zhí)行onUnload說明之前的頁面還在搀别,而每次打開C都執(zhí)行了onLoad/onShow/onReady說明我們打開的是一個(gè)新的頁面丹擎,但是打開控制臺看頁面棧信息,截圖如下:
trace
頁面棧樹中只有A和C兩個(gè)歇父,不過我們跳轉(zhuǎn)時(shí)打開這里可以看到C的__webviewId__是在變化的蒂培,也證明了我們打開的是一個(gè)新的頁面。雖然從控制臺AppData的Tree看上去有要兩個(gè)榜苫,實(shí)際上我們跳轉(zhuǎn)夠10次還是會受到微信頁面深度最大為10層的限制护戳。下面按微信左上角的返回鍵,看下生命周期流程:
Cback
可以看到依次執(zhí)行了C頁面的onUnload/onShow垂睬,也就是之前的多個(gè)C頁面被一一卸載掉了媳荒。這里注意一點(diǎn),對于二級頁面驹饺,使用navigateBake或者微信自己的返回按鍵都會卸載掉當(dāng)前頁面钳枕,所以離開頁面只有navigateTo的時(shí)候會保留當(dāng)前頁面,其他情況都會卸載掉當(dāng)前頁面赏壹。(自我總結(jié):對于二級頁面鱼炒,只有從下一個(gè)頁面返回自身的情況下,不調(diào)用onLoad其他任何情況進(jìn)入二級頁面蝌借,都會觸發(fā)onLoad昔瞧。沒有想到其他情況指蚁,顧作此總結(jié),歡迎指正)硬爆。

組件的生命周期函數(shù)

小程序支持自定義組件欣舵,使用Component構(gòu)造器定義組件,使用Component構(gòu)造器時(shí)可以定義組件的屬性缀磕、數(shù)據(jù)缘圈、方法等。這里整理下生命周期相關(guān)函數(shù)袜蚕。
組件的生命周期函數(shù)有兩種形式糟把,除了寫在外面,還可以統(tǒng)一寫在lifetimes中牲剃,在下面的示例代碼備注中可以看到遣疯。
    Component({
        properties:{
            innerText:{
                type:String
            }
        },
        data:{

        },
        methods:{

        },
        created:function(){
            // 組件生命周期函數(shù),在組件實(shí)例進(jìn)入頁面節(jié)點(diǎn)樹時(shí)執(zhí)行凿傅,注意此時(shí)不能調(diào)用setData
            console.log('Component-1 >> created');
        },
        attached:function(){
            // 組件生命周期函數(shù)缠犀,在組件實(shí)例進(jìn)入頁面節(jié)點(diǎn)樹時(shí)執(zhí)行。
            console.log('Component-1 >> attached');
        },
        ready:function(){
            // 在組件布局完成后執(zhí)行聪舒,此時(shí)可以獲取節(jié)點(diǎn)信息
            console.log('Component-1 >> ready');
        },
        moved:function(){
            // 在組件實(shí)例被移動(dòng)到節(jié)點(diǎn)樹另一個(gè)位置時(shí)執(zhí)行
            console.log('Component-1 >> moved');
        },
        detached:function(){
            // 在組件實(shí)例被從頁面節(jié)點(diǎn)樹移除時(shí)執(zhí)行
            console.log('Component-1 >> detached');
        },
        lifetimes:{
            // 組件生命周期聲明對象辨液,將組件的生命周期收歸到該字段進(jìn)行聲明,原有聲明方式仍舊有效箱残,如同時(shí)存在兩種聲明方式滔迈,則lifetimes字段內(nèi)聲明方式優(yōu)先級最高
            created:function(){
                console.log('Component-1 lifetimes >> created');
            },
            attached:function(){
                console.log('Component-1 lifetimes >> attached');
            },
            ready:function(){
                console.log('Component-1 lifetimes >> ready');
            },
            moved:function(){
                console.log('Component-1 lifetimes >> moved');
            },
            detached:function(){
                console.log('Component-1 lifetimes >> detached');
            }
        },
        pageLifetimes:{
            // 組件所在頁面的生命周期聲明對象,目前僅支持頁面的show和hide兩個(gè)生命周期
            show:function(){
                console.log('Component-1 pageLifetimes >> Show');
            },
            hide:function(){
                console.log('Component-1 pageLifetimes >> Hide');
            }
        }

    })

分別在B頁面和C頁面引入該組件被辑, 從以下幾種情況看下生命周期函數(shù)的執(zhí)行過程

第一種情況同時(shí)引入上面所有生命周期函數(shù)燎悍,由A通過tab切換到B,再由B通過navigateTo切換到C盼理,生命周期執(zhí)行打印如下:

Components
可以看到組件中只執(zhí)行了lifetimes中的生命周期函數(shù)谈山,外層的生命周期函數(shù)并沒有執(zhí)行。而且可以看到先執(zhí)行組件的created/attached函數(shù)榜揖,隨后執(zhí)行頁面的onLoad/onShow勾哩,再執(zhí)行組件的ready,最后執(zhí)行頁面的onReady举哟,這是頁面中引入組件時(shí)組件的生命周期函數(shù)執(zhí)行順序。
lifetimes中的生命周期函數(shù)執(zhí)行了迅矛,外層的生命周期函數(shù)沒有執(zhí)行妨猩,所有當(dāng)兩者同時(shí)存在時(shí),lifetimes中的優(yōu)先級要高秽褒。
這里組件中的pageLifetimes沒有執(zhí)行壶硅,不清楚具體原因威兜,官網(wǎng)說是2.2.3版本以上支持,我在2.3.0的環(huán)境還是沒有執(zhí)行庐椒,不清楚具體原因椒舵,求解!

第二種情況约谈,不引入lifetimes的生命周期函數(shù)笔宿,只使用外層的生命周期函數(shù),執(zhí)行結(jié)果如下圖所示:

COMPONENT
可以看到棱诱,生命周期函數(shù)執(zhí)行順序沒有變泼橘,外層的生命周期生效。

第三種情況迈勋,在B頁面中使用兩個(gè)組件炬灭,這里我把lifetimes中的created生命周期注釋掉了,看生命周期的執(zhí)行情況靡菇,這里組件1和組件2的代碼相同重归,執(zhí)行結(jié)果情況如下圖:

image.png
從執(zhí)行的結(jié)果來看,整個(gè)生命周期的執(zhí)行順序不變厦凤,只是要在每個(gè)階段執(zhí)行所有組件的相應(yīng)生命周期鼻吮,如上圖,現(xiàn)行玩所有組件的created泳唠,再執(zhí)行所有組件的attached,然后執(zhí)行頁面的onLoad和onShow狈网,再執(zhí)行所有組件的ready,最后執(zhí)行頁面的onReady笨腥。

總結(jié):通過這些試驗(yàn)拓哺,對小程序相關(guān)的生命周期有了一個(gè)基本的認(rèn)識。

1脖母、小程序初次打開會執(zhí)行小程序的生命周期鉤子函數(shù):onLaunch->onShow士鸥,而且這些鉤子函數(shù)只會執(zhí)行一次。關(guān)閉小程序谆级,小程序并不會真正退出烤礁,所以執(zhí)只行了onHide
2肥照、頁面的初次打開會執(zhí)行頁面的生命周期鉤子函數(shù):onLoad->onShow->onReady脚仔,通過navigateTo離開頁面會保留該頁面,此時(shí)只執(zhí)行onHide舆绎,其他方式離開(包括navigateBack)都會干掉當(dāng)前頁面鲤脏,此時(shí)會執(zhí)行onHide>onUnload。特殊情況:switchTabTo會干掉所有非tab頁面,但是保留所有已經(jīng)加載的tab頁面猎醇。
3窥突、包含組件的頁面,先執(zhí)行所有組件的created硫嘶,再執(zhí)行所有組件的attached阻问,然后執(zhí)行頁面的onLoad>onshow,再執(zhí)行所有組件的ready沦疾,隨后執(zhí)行頁面的onReady称近。當(dāng)頁面被卸載時(shí),先執(zhí)行頁面的onUnload曹鸠,再執(zhí)行組件的detached煌茬。頁面不卸載,不會觸發(fā)組件的detached彻桃。

初次接觸小程序坛善,能力有限,歡迎指正邻眷![/抱拳]

參考文檔:https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/component.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末眠屎,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子肆饶,更是在濱河造成了極大的恐慌改衩,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件驯镊,死亡現(xiàn)場離奇詭異葫督,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)板惑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門橄镜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人冯乘,你說我怎么就攤上這事洽胶。” “怎么了裆馒?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵姊氓,是天一觀的道長。 經(jīng)常有香客問我喷好,道長翔横,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任梗搅,我火速辦了婚禮棕孙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘些膨。我一直安慰自己蟀俊,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布订雾。 她就那樣靜靜地躺著肢预,像睡著了一般。 火紅的嫁衣襯著肌膚如雪洼哎。 梳的紋絲不亂的頭發(fā)上烫映,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天,我揣著相機(jī)與錄音噩峦,去河邊找鬼锭沟。 笑死,一個(gè)胖子當(dāng)著我的面吹牛识补,可吹牛的內(nèi)容都是我干的族淮。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼凭涂,長吁一口氣:“原來是場噩夢啊……” “哼祝辣!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起切油,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蝙斜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后澎胡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體孕荠,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年攻谁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了稚伍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,090評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡巢株,死狀恐怖槐瑞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情阁苞,我是刑警寧澤困檩,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站那槽,受9級特大地震影響悼沿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜骚灸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一糟趾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦义郑、人聲如沸蝶柿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽交汤。三九已至,卻和暖如春劫笙,著一層夾襖步出監(jiān)牢的瞬間芙扎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工填大, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留戒洼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓允华,卻偏偏與公主長得像圈浇,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子例获,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容