# 小程序運行機制
# 1. 小程序的生命周期
小程序從啟動到最終被銷毀,會經(jīng)歷很多不同的狀態(tài),小程序在不同狀態(tài)下會有不同的表現(xiàn)。
# 1.1 小程序啟動
從用戶認知的角度看,廣義的小程序啟動可以分為兩種情況,一種是冷啟動,一種是熱啟動。
- 冷啟動:如果用戶首次打開,或小程序銷毀后被用戶再次打開,此時小程序需要重新加載啟動,即冷啟動。
- 熱啟動:如果用戶已經(jīng)打開過某小程序,然后在一定時間內(nèi)再次打開該小程序,此時小程序并未被銷毀,只是從后臺狀態(tài)進入前臺狀態(tài),這個過程就是熱啟動。
從小程序生命周期的角度來看,我們一般講的「啟動」專指冷啟動,熱啟動一般被稱為后臺切前臺。
# 1.2 前臺與后臺
小程序啟動后,界面被展示給用戶,此時小程序處于「前臺」狀態(tài)。
當用戶「關(guān)閉」小程序時,小程序并沒有真正被關(guān)閉,而是進入了「后臺」狀態(tài),此時小程序還可以短暫運行一小段時間,但部分 API 的使用會受到限制。切后臺的方式包括但不限于以下幾種:
- 點擊右上角膠囊按鈕離開小程序
- iOS 從屏幕左側(cè)右滑離開小程序
- 安卓點擊返回鍵離開小程序
- 小程序前臺運行時直接把微信切后臺(手勢或 Home 鍵)
- 小程序前臺運行時直接鎖屏
當用戶再次進入微信并打開小程序,小程序又會重新進入「前臺」狀態(tài)。
# 1.3 掛起
小程序進入「后臺」狀態(tài)一段時間后(目前是 5 秒),微信會停止小程序 JS 線程的執(zhí)行,小程序進入「掛起」狀態(tài)。此時小程序的內(nèi)存狀態(tài)會被保留,但開發(fā)者代碼執(zhí)行會停止,事件和接口回調(diào)會在小程序再次進入「前臺」時觸發(fā)。
當開發(fā)者使用了后臺音樂播放、后臺地理位置等能力時,小程序可以在「后臺」持續(xù)運行,不會進入到「掛起」狀態(tài)
# 1.4 小程序銷毀
如果用戶很久沒有使用小程序,或者系統(tǒng)資源緊張,小程序會被「銷毀」,即完全終止運行。具體而言包括以下幾種情形:
- 當小程序進入后臺并被「掛起」后,如果很長時間(目前是 30 分鐘)都未再次進入前臺,小程序會被銷毀。
- 當小程序占用系統(tǒng)資源過高,可能會被系統(tǒng)銷毀或被微信客戶端主動回收。
- 在 iOS 上,當微信客戶端在一定時間間隔內(nèi)連續(xù)收到系統(tǒng)內(nèi)存告警時,會根據(jù)一定的策略,主動銷毀小程序,并提示用戶 「運行內(nèi)存不足,請重新打開該小程序」。具體策略會持續(xù)進行調(diào)整優(yōu)化。
- 建議小程序在必要時使用 wx.onMemoryWarning 監(jiān)聽內(nèi)存告警事件,進行必要的內(nèi)存清理。
基礎(chǔ)庫 1.1.0 及以上,1.4.0 以下版本: 當用戶從掃一掃、轉(zhuǎn)發(fā)等入口(場景值為1007, 1008, 1011, 1025)進入小程序,且沒有置頂小程序的情況下退出,小程序會被銷毀。
# 2. 小程序冷啟動的頁面
小程序冷啟動時,打開的頁面有以下情況
- (A 類場景)若啟動的場景中不帶 path
- 基礎(chǔ)庫 2.8.0 以下版本,進入首頁
- 基礎(chǔ)庫 2.8.0 及以上版本遵循「重新啟動策略」,可能是首頁或上次退出的頁面
- (B 類場景)若啟動的場景中帶有 path,則啟動進入對應(yīng) path 的頁面
# 2.1 重新啟動策略
基礎(chǔ)庫 2.8.0 開始支持,低版本需做兼容處理。
小程序冷啟動時,如果啟動時不帶 path(A 類場景),默認情況下將會進入小程序的首頁。
在頁面對應(yīng)的 json 文件中(也可以全局配置在 app.json 的 window 段中),指定 restartStrategy 配置項可以改變這個默認的行為,使得從某個頁面退出后,下次 A 類場景的冷啟動可以回到這個頁面。
代碼示例:
{
"restartStrategy": "homePage"
}
restartStrategy 可選值:
| 可選值 | 含義 |
|---|---|
| homePage | (默認值)如果從這個頁面退出小程序,下次將從首頁冷啟動 |
| homePageAndLatestPage | 如果從這個頁面退出小程序,下次冷啟動后立刻加載這個頁面,頁面的參數(shù)保持不變(不可用于 tab 頁) |
注意:即使不配置為 homePage ,小程序如果退出過久(當前默認一天時間,可以使用退出狀態(tài)來調(diào)整),下次冷啟動時也將不再遵循 restartStrategy 的配置,而是直接從首頁冷啟動。
無論如何,頁面中的狀態(tài)并不會被保留,如輸入框中的文本內(nèi)容、 checkbox 的勾選狀態(tài)等都不會還原。如果需要還原或部分還原,需要利用退出狀態(tài)。
# 3. 小程序熱啟動的頁面
小程序熱啟動時,打開的頁面有以下情況
- (A 類場景)若啟動的場景中不帶 path,則保留上次的瀏覽的狀態(tài)
- (B 類場景)若啟動的場景中帶有 path,則 reLaunch 到對應(yīng) path 的頁面
A 類場景常見的有下列場景值:
| 場景值ID | 說明 |
|---|---|
| 1001 | 發(fā)現(xiàn)欄小程序主入口,「最近使用」列表(基礎(chǔ)庫2.2.4版本起包含「我的小程序」列表) |
| 1003 | 星標小程序列表 |
| 1023 | 系統(tǒng)桌面小圖標打開小程序 |
| 1038 | 從其他小程序返回小程序 |
| 1056 | 聊天頂部音樂播放器右上角菜單,打開小程序 |
| 1080 | 客服會話菜單小程序入口,打開小程序 |
| 1083 | 公眾號會話菜單小程序入口 ,打開小程序(只有騰訊客服小程序有) |
| 1089 | 聊天主界面下拉,打開小程序/微信聊天主界面下拉,「最近使用」欄(基礎(chǔ)庫2.2.4版本起包含「我的小程序」欄) |
| 1090 | 長按小程序右上角菜單,打開小程序 |
| 1103 | 發(fā)現(xiàn)-小程序主入口我的小程序,打開小程序 |
| 1104 | 聊天主界面下拉,從我的小程序,打開小程序 |
| 1113 | 安卓手機負一屏,打開小程序 |
| 1114 | 安卓手機側(cè)邊欄,打開小程序 |
| 1117 | 后臺運行小程序的管理頁中,打開小程序 |
# 4. 退出狀態(tài)
基礎(chǔ)庫 2.7.4 開始支持,低版本需做兼容處理。
每當小程序可能被銷毀之前,頁面回調(diào)函數(shù) onSaveExitState 會被調(diào)用。如果想保留頁面中的狀態(tài),可以在這個回調(diào)函數(shù)中“保存”一些數(shù)據(jù),下次啟動時可以通過 exitState 獲得這些已保存數(shù)據(jù)。
代碼示例:
{
"restartStrategy": "homePageAndLatestPage"
}
Page({
onLoad: function() {
var prevExitState = this.exitState // 嘗試獲得上一次退出前 onSaveExitState 保存的數(shù)據(jù)
if (prevExitState !== undefined) { // 如果是根據(jù) restartStrategy 配置進行的冷啟動,就可以獲取到
prevExitState.myDataField === 'myData'
}
},
onSaveExitState: function() {
var exitState = { myDataField: 'myData' } // 需要保存的數(shù)據(jù)
return {
data: exitState,
expireTimeStamp: Date.now() + 24 * 60 * 60 * 1000 // 超時時刻
}
}
})
onSaveExitState 返回值可以包含兩項:
| 字段名 | 類型 | 含義 |
|---|---|---|
| data | Any | 需要保存的數(shù)據(jù)(只能是 JSON 兼容的數(shù)據(jù)) |
| expireTimeStamp | Number | 超時時刻,在這個時刻后,保存的數(shù)據(jù)保證一定被丟棄,默認為 (當前時刻 + 1 天) |
一個更完整的示例:在開發(fā)者工具中預(yù)覽效果
# 注意事項
- 如果超過
expireTimeStamp,保存的數(shù)據(jù)將被丟棄,且冷啟動時不遵循restartStrategy的配置,而是直接從首頁冷啟動。 expireTimeStamp有可能被自動提前,如微信客戶端需要清理數(shù)據(jù)的時候。- 在小程序存活期間,
onSaveExitState可能會被多次調(diào)用,此時以最后一次的調(diào)用結(jié)果作為最終結(jié)果。 - 在某些特殊情況下(如微信客戶端直接被系統(tǒng)殺死),這個方法將不會被調(diào)用,下次冷啟動也不遵循
restartStrategy的配置,而是直接從首頁冷啟動。