欧美日韩精品一区二区在线线,一级无码在线收看,精品国产高清91,久久精品欧美电影

# 頁(yè)面切換優(yōu)化

頁(yè)面切換的性能影響用戶操作的連貫性和流暢度,是小程序運(yùn)行時(shí)性能的一個(gè)重要組成部分。

# 1. 頁(yè)面切換的流程

要想優(yōu)化頁(yè)面切換的性能,有必要先簡(jiǎn)單了解下小程序頁(yè)面切換的過(guò)程。頁(yè)面切換流程如圖所示:

開發(fā)者可以通過(guò)wx.getPerformance接口中 entryType 為 navigation,name 為 route 的指標(biāo)(PerformanceEntry),獲取頁(yè)面切換耗時(shí)時(shí)。

當(dāng)切換的目標(biāo)頁(yè)面已加載完成時(shí)(例如:路由類型為 navigateBack,或 switchTab 到一個(gè)已加載的頁(yè)面),不需要進(jìn)行「視圖層頁(yè)面初始化」和「目標(biāo)頁(yè)面渲染」,「邏輯層頁(yè)面初始化」也會(huì)較為簡(jiǎn)化,如下圖所示:

# 1.1 觸發(fā)頁(yè)面切換

頁(yè)面切換的流程,從用戶觸發(fā)頁(yè)面切換開始。

觸發(fā)時(shí)間對(duì)應(yīng) PerformanceEntry(route) 中的 startTime。

頁(yè)面切換可能由以下幾類操作觸發(fā):

  • 小程序API調(diào)用:開發(fā)者根據(jù)用戶操作,調(diào)用 wx.navigateTo、wx.navigateBackwx.redirectTo、wx.reLaunch、wx.switchTab 等 API。
  • 用戶點(diǎn)擊 <navigator> 組件進(jìn)行頁(yè)面切換。
  • 用戶點(diǎn)擊原生 UI 觸發(fā):例如點(diǎn)擊 tabBar(自定義 tabBar 除外)、點(diǎn)擊左上角「返回首頁(yè)」按鈕、點(diǎn)擊系統(tǒng)返回鍵或左滑返回等。
  • 小程序熱啟動(dòng)時(shí)自動(dòng) reLaunch:小程序熱啟動(dòng)的 B 類場(chǎng)景

目前后兩種情況暫時(shí)未能獲取準(zhǔn)確的觸發(fā)時(shí)間,PerformanceEntry(route) 的 startTime 和 navigationStart 一致。

# 1.2 加載分包(若有)

如果頁(yè)面切換的目標(biāo)頁(yè)面在分包中,頁(yè)面切換時(shí)需要下載分包,并在邏輯層注入執(zhí)行分包內(nèi)的 JS 代碼。

小程序生命周期內(nèi),每個(gè)分包只會(huì)在邏輯層注入一次。

# 1.3 視圖層頁(yè)面初始化

小程序視圖層的每個(gè)頁(yè)面都是由獨(dú)立的 WebView 渲染的,因此頁(yè)面切換時(shí)需要一個(gè)新的 WebView 環(huán)境。視圖層頁(yè)面初始化主要會(huì)做以下事情:

  • 創(chuàng)建 WebView
  • 注入視圖層的小程序基礎(chǔ)庫(kù)
  • 注入主包的公共代碼(獨(dú)立分包除外)
  • (若頁(yè)面位于分包中)注入分包的公共代碼
  • 注入頁(yè)面代碼

為了降低視圖層頁(yè)面初始化的耗時(shí),在頁(yè)面渲染完成后,通常會(huì)進(jìn)行必要的預(yù)加載供頁(yè)面切換時(shí)使用。預(yù)加載主要會(huì)做以下事情:

  • 創(chuàng)建 WebView
  • 注入視圖層的小程序基礎(chǔ)庫(kù)
  • 注入主包的公共代碼(若主包已在本地)

如果頁(yè)面切換過(guò)快,或預(yù)加載的環(huán)境被回收,則需要在頁(yè)面切換時(shí)重新創(chuàng)建環(huán)境。

如果頁(yè)面切換時(shí)有預(yù)加載好的環(huán)境,可以大大降低頁(yè)面切換的耗時(shí)。

當(dāng)切換的目標(biāo)頁(yè)面已加載完成時(shí),不需要進(jìn)行本階段。

# 1.4 邏輯層頁(yè)面初始化

完成分包加載和 WebView 創(chuàng)建后,客戶端會(huì)向基礎(chǔ)庫(kù)派發(fā)路由事件。

基礎(chǔ)庫(kù)收到事件后會(huì)進(jìn)行邏輯層的頁(yè)面初始化,包括觸發(fā)上一個(gè)頁(yè)面的 onHide/onUnload、頁(yè)面組件樹初始化、更新頁(yè)面棧并生成初始數(shù)據(jù)發(fā)送到視圖層,并依次觸發(fā)目標(biāo)的 onLoad, onShow 生命周期。如果啟用了「按需注入」,這一階段還會(huì)注入頁(yè)面代碼。

基礎(chǔ)庫(kù)收到事件的時(shí)間對(duì)應(yīng) PerformanceEntry(route) 中的 navigationStart,對(duì)應(yīng) PerformanceEntry(firstRender) 的開始時(shí)間。

當(dāng)切換的目標(biāo)頁(yè)面已加載完成時(shí),不需進(jìn)行頁(yè)面組件樹初始化和初始數(shù)據(jù)的發(fā)送,且不會(huì)觸發(fā)目標(biāo)頁(yè)面的 onLoad

# 1.5 目標(biāo)頁(yè)面渲染

頁(yè)面切換的目標(biāo)頁(yè)面不存在時(shí),會(huì)觸發(fā)頁(yè)面的首次渲染。

在完成視圖層代碼注入,并收到邏輯層發(fā)送的初始數(shù)據(jù)后,結(jié)合從初始數(shù)據(jù)和視圖層得到的頁(yè)面結(jié)構(gòu)和樣式信息,小程序框架會(huì)進(jìn)行頁(yè)面渲染,并觸發(fā)頁(yè)面的 onReady 事件。

視圖層渲染完成,觸發(fā)頁(yè)面 onReady 事件的時(shí)間,對(duì)應(yīng) PerformanceEntry(firstRender) 的結(jié)束時(shí)間。

當(dāng)切換的目標(biāo)頁(yè)面已加載完成時(shí),不需要進(jìn)行本階段。

# 1.6 頁(yè)面切換動(dòng)畫

頁(yè)面渲染完成后,客戶端會(huì)進(jìn)行頁(yè)面切換的動(dòng)畫(如:從右向左推入頁(yè)面)。如果頁(yè)面初始化和渲染的時(shí)間超過(guò)固定時(shí)間,為避免用戶以為頁(yè)面無(wú)響應(yīng),頁(yè)面會(huì)提前推入。

頁(yè)面推入動(dòng)畫完成的時(shí)間,對(duì)應(yīng) PerformanceEntry(route) 的結(jié)束時(shí)間。

# 2. 如何優(yōu)化頁(yè)面切換

# 2.1 避免在 onHide/onUnload 執(zhí)行耗時(shí)操作

頁(yè)面切換時(shí),會(huì)先調(diào)用前一個(gè)頁(yè)面的 onHide 或 onUnload 生命周期,然后再進(jìn)行新頁(yè)面的創(chuàng)建和渲染。如果 onHide 和 onUnload 執(zhí)行過(guò)久,可能導(dǎo)致頁(yè)面切換的延遲。

  • ? onHide/onUnload 中的邏輯應(yīng)盡量簡(jiǎn)單,若必須要進(jìn)行部分復(fù)雜邏輯,可以考慮用 setTimeout 延遲進(jìn)行。
  • ? 減少或避免在 onHide/onUnload 中執(zhí)行耗時(shí)邏輯,如同步接口調(diào)用、setData 等。

# 2.2 首屏渲染優(yōu)化

頁(yè)面首屏渲染是頁(yè)面切換耗時(shí)的重要組成部分,優(yōu)化手段可以參考啟動(dòng)性能優(yōu)化中首屏渲染優(yōu)化部分。

# 2.3 提前發(fā)起數(shù)據(jù)請(qǐng)求

在一些對(duì)性能要求比較高的場(chǎng)景下,當(dāng)使用 JSAPI 進(jìn)行頁(yè)面跳轉(zhuǎn)時(shí)(例如 wx.navigateTo),可以提前為下一個(gè)頁(yè)面做一些準(zhǔn)備工作。頁(yè)面之間可以通過(guò) EventChannel 進(jìn)行通信。

例如,在頁(yè)面跳轉(zhuǎn)時(shí),可以同時(shí)發(fā)起下一個(gè)頁(yè)面的數(shù)據(jù)請(qǐng)求,而不需要等到頁(yè)面 onLoad 時(shí)再進(jìn)行,從而可以讓用戶更早的看到頁(yè)面內(nèi)容。尤其是在跳轉(zhuǎn)到分包頁(yè)面時(shí),從發(fā)起頁(yè)面跳轉(zhuǎn)到頁(yè)面 onLoad 之間可能有較長(zhǎng)的時(shí)間間隔,可以加以利用。

# 2.4 控制預(yù)加載下個(gè)頁(yè)面的時(shí)機(jī)

基礎(chǔ)庫(kù) 2.15.0 開始支持,僅安卓。低版本配置不生效。

如 1.3 節(jié)所述,小程序頁(yè)面加載完成后,會(huì)預(yù)加載下一個(gè)頁(yè)面。默認(rèn)情況下,小程序框架會(huì)在當(dāng)前頁(yè)面 onReady 觸發(fā) 200ms 后觸發(fā)預(yù)加載。

在安卓上,小程序渲染層所有頁(yè)面的 WebView 共享同一個(gè)線程。很多情況下,小程序的初始數(shù)據(jù)只包括了頁(yè)面的大致框架,并不是完整的內(nèi)容。頁(yè)面主體部分需要依靠 setData 進(jìn)行更新。因此,預(yù)加載下一個(gè)頁(yè)面可能會(huì)阻塞當(dāng)前頁(yè)面的渲染,造成 setData 和用戶交互出現(xiàn)延遲,影響用戶看到頁(yè)面完整內(nèi)容的時(shí)機(jī)。

為了讓用戶能夠更早看到完整的頁(yè)面內(nèi)容,避免預(yù)加載流程對(duì)頁(yè)面加載過(guò)程的影響,開發(fā)者可以配置 handleWebviewPreload 選項(xiàng),來(lái)控制預(yù)加載下個(gè)頁(yè)面的時(shí)機(jī)。

handleWebviewPreload 有以下取值

  • static: 默認(rèn)值。在當(dāng)前頁(yè)面 onReady 觸發(fā) 200ms 后觸發(fā)預(yù)加載。
  • auto: 渲染線程空閑時(shí)進(jìn)行預(yù)加載。由基礎(chǔ)庫(kù)根據(jù)一段時(shí)間內(nèi) requestAnimationFrame 的觸發(fā)頻率算法判斷。
  • manual: 由開發(fā)者通過(guò)調(diào)用 wx.preloadWebview 觸發(fā)。開發(fā)者可以在頁(yè)面主要內(nèi)容的 setData 結(jié)束后手動(dòng)觸發(fā)。

例如:

在 app.json 中(作用于全局控制)

{
  "window": {
    "handleWebviewPreload": "auto"
  }
}

或在頁(yè)面 JSON 文件中(只作用于單個(gè)頁(yè)面)

{
  "handleWebviewPreload": "manual"
}
Page({
  onLoad() {
    this.setData({
      fullData: {}
    }, () => {
      // 只有配置為 manual 時(shí)需要調(diào)用
      wx.preloadWebview?.()
    })
  }
})

如下圖所示,假設(shè)某小程序主頁(yè)完整內(nèi)容是分了三個(gè) setData 進(jìn)行的: