小程序技能進階回憶錄 - 如何改變 onLoad 的執行時機

人活着,總得要點英雄主義的,哪怕失敗、死亡。前端

也許在小程序全部生命週期裏,咱們用的最多的就是 onLoad,一大堆代碼都要在初始化的時候執行。小程序

不少時候,初始化的代碼是每一個頁面共用的,好比獲取用戶信息、獲取定位等:微信

Page({
  onLoad() {
    this.userData = getUserData()
    wx.getLocation({
      type: 'wgs84',
      success (res) {
        // 業務代碼
        // ...
      }
    })
  }
  // ...
})
複製代碼

長此以往,每一個頁面的 js 裏都是如上的重複代碼。若是能夠先執行完通用的初始化代碼,再執行每一個頁面各自的 onLoad 多好,惋惜小程序並無提供相似的鉤子函數,那就本身來吧。框架

代理 onLoad

按照前幾篇的方法,能夠代理原有的 onLoad 事件:異步

var originPage = Page

function MyPage(config) {
  this.lifetimeBackup = {
    onLoad: config.onLoad
  }
  config.onLoad = function(options) {
    // 自定義代碼
    // 公共的初始化代碼
    this.userData = getUserData()
     wx.getLocation({
      type: 'wgs84',
      success (res) {
        // 執行 onLoad
        this.lifetimeBackup.onLoad.call(this, options)
      }
    })
  }
  
  // ...

  originPage(config)
}
複製代碼

固然,實際開發過程當中的初始化代碼不可能這麼少,能夠用不少方式把它抽離出去,好比這樣:函數

// utils/initial.js
function initial(callback) {
  this.userData = getUserData()
  wx.getLocation({
    type: 'wgs84',
    success (res) {
      callback()
    }
  })
}
  
// utils/wx.js
var initial = require('./initial')
var originPage = Page

function MyPage(config) {
  this.lifetimeBackup = {
    onLoad: config.onLoad
  }
  config.onLoad = function(options) {
    initial(() => {
      this.lifetimeBackup.onLoad.call(this, options)
    })
  }
  // ...
  originPage(config)
}
複製代碼

也可使用更多高級的方法抽離出去,好比 event bus 之類的,就很少贅述。組件化

看似很簡單,但其實這樣忽略了一個問題 —— 生命週期順序被打亂了!若是初始化方法裏有異步代碼,那首先執行的可能就是 onShow ,而不是約定的 onLoadpost

恢復生命週期順序

爲了保證生命週期函數可以按順序執行,能夠先臨時清空生命週期函數,而後再依次執行,以下代碼所示:ui

// utils/wx.js
const LIFETIME_EVENTS = ['onLoad', 'onShow', 'onReady']
var initial = require('./initial')
var originPage = Page


function MyPage(config) {
  LIFETIME_EVENTS.forEach((event) => {
    // 備份生命週期函數
    this.lifetimeBackup[event] = config[event]
    // 臨時清空
    config[event] = function() {}
  })
  config.onLoad = function(options) {
    initial(() => {
      // 依次執行生命週期函數
      LIFETIME_EVENTS.forEach((event) => {
        this.lifetimeBackup[event].call(this, options)
      })
    })
  }
  // ...
  originPage(config)
}
複製代碼

注意上述代碼仍是有問題的,當小程序業務跳走再返回或者切後臺到前臺時,onShow 沒法正常觸發,由於被設置爲空函數了。this

爲了保證 onShow 等生命週期函數的後續正常運行,須要在依次執行完生命週期函數後,再把它們恢復到 config 下,這是必不可少的。完整代碼以下:

// utils/wx.js
const LIFETIME_EVENTS = ['onLoad', 'onShow', 'onReady']
var initial = require('./initial')
var originPage = Page


function MyPage(config) {
  LIFETIME_EVENTS.forEach((event) => {
    // 備份生命週期函數
    this.lifetimeBackup[event] = config[event]
    // 臨時清空
    config[event] = function() {}
  })
  config.onLoad = function(options) {
    initial(() => {
      // 依次執行生命週期函數
      LIFETIME_EVENTS.forEach((event) => {
        this.lifetimeBackup[event].call(this, options)
        // 執行完後,恢復過來
        config[event] = this.lifetimeBackup[event]
      })
    })
  }
  // ...
  originPage(config)
}
複製代碼

總結

代理了 onLoad 後,就能夠手動控制其執行的時機,能夠折騰的事情就多了不少。好比當初始化函數須要執行(請求)的內容比較多,耗時比較長時,能夠統一給頁面增長一些 loading 提示等。總之,能夠自由控制了。

傳送門

廣告時間

美團單車事業部(摩拜單車)誠招前端 / 小程序研發工程師,位置北京,有興趣能夠發簡歷到 zhangshibing@mobike.com 或者掃二維碼先加微信勾搭:)

相關文章
相關標籤/搜索