1. 程式人生 > >好玩的JS系列--小程式資料埋點

好玩的JS系列--小程式資料埋點

小編推薦:Fundebug專注於JavaScript、微信小程式、微信小遊戲,Node.js和Java實時BUG監控。真的是一個很好用的bug監控費服務,眾多大佬公司都在使用。

前言

  最近負責的一個專案,專案的客戶端是微信小程式。客戶提了需求,需要進行資料埋點,收集使用者行為資料,為後續提升使用者體驗及產品優化提供基礎資料收集。於是在一個風和日麗的日子,擼起袖子動手幹。

思路

  先看看客戶端常見的資料埋點方案如下圖。

資料埋點方案.png


  侵入式埋點這個如果在頁面少,資料收集需求變化不大的情況下,還是挺經濟實惠的。鑑於當前專案頁面較多,資料收集的需求變化也在不斷的調整,所以侵入式埋點的方案不適用本專案,只有鬆耦合這個方案了。

 

小程式的特點

  根據鬆耦合埋點方案,首先要解決的問題是攔截小程式所有控制元件的操作資料。在Web中有BOM物件及DOM物件可以給我們進行全方位的操作,特別是BOM物件,可以進行全域性事件攔截。而小程式類似BOM物件的主要有下面三個物件:App、Page、Component。

  • App:App物件有且只有一個,屬於小程式的總控物件,App下面包含著n個Page物件。
  • Page:Page則通過字面理解就是頁面的總控物件,一個小程式可以有多個Page,每一個Page物件對應一個頁面,Page下面可以包含n個Component及其他普通的小程式元件。
  • Component:
    Component則是自定義元件物件,類似於Page,只明生命週期及一些特性上有所區別,自定義元件物件在實際專案中比較常用,主要用來解決小程式頁面堆疊太小的問題,這個後續再寫另外一篇來講。

  小程式的事件機制也是採用與JavaScript一樣的事件機制,捕獲->執行->冒泡的機制,JavaScript在BOM及DOM物件中都提供了addEventListener這種訂閱/釋出機制,使我們可以輕鬆的攔截所有的事件,又不影響現有的流程及程式碼,從而實現鬆耦合埋點方案。但是小程式沒有提供addEventListener的訂閱/釋出機制,沒有辦法通過這樣子的方案來實現。

1.攔截器方式

翻了官網,發現沒有辦法統一的處理,那麼只能退而求其次,減少對現有的程式碼的侵入,於是想到了攔截器的機制來實現。

  看看下面小程式原生的程式碼

App({
  onLaunch(options) {
    // Do something initial when launch.
  },
  onShow(options) {
    // Do something when show.
  },
  onHide() {
    // Do something when hide.
  },
  onError(msg) {
    console.log(msg)
  },
  globalData: 'I am global data'
})

  提供攔截器,這裡只拿App的onLaunch事件進行示例,其他事件都差不多這樣處理即可。

var appFilter = function(config){
  if(config.onLaunch){
    let _onLaunch = config.onLaunch;
    config.onLaunch = function(ops){
         //在這裡幹埋點的事
        //例如儲存資料、上送資料
         _onLaunch.call(this);//呼叫原來的執行邏輯
    }
  }
  return config;
}


//App使用攔截器示例
App(appFilter({
  onLaunch(options) {
    // Do something initial when launch.
  },
  onShow(options) {
    // Do something when show.
  },
  onHide() {
    // Do something when hide.
  },
  onError(msg) {
    console.log(msg)
  },
  globalData: 'I am global data'
})
)

  這個也是JS好玩的地方,一切皆為物件。通過新增一個Function物件,增強方法之後,把舊的Function物件進行替換。上面的App的onLaunch方法,經過appFilter過濾器的處理後,就替換成過濾器裡面加了埋點事件的新方法了,對於開發人員來講,不需要去改動原來App.onLaunch事件裡面的程式碼,目的達到了,但是不夠完美,在寫過濾器的實現邏輯時,給了我一個靈感,我是否可以用這種方式來實現不侵入程式碼的埋點?答案是可以的。

2.增強擴充套件方式

  利用新增一個Function物件,增強方法之後,把舊的Function物件進行替換這樣的原理,依次將App、Page、Component這三個物件進行增強擴充套件,示例程式碼如下。

//先把原生的三個物件儲存起來
const originalApp = App,
      originalPage = Page,
      originalComponent = Component;
//在原生的事件函式裡面,新增資料埋點,並替換成新的事件函式
const _extendsApp = function (conf, method) {
  const _o_method = conf[method];
  conf[method] = function (ops) {
    //在此處進行資料埋點
    if (typeof _o_method === 'function') {
      _o_method.call(this, ops);
    }
  }
}

//重新定義App這個物件,將原來的App物件覆蓋
App = function(conf){
  //定義需要增強的方法
  const methods = ['onLaunch', 'onShow', 'onHide', 'onError']

  methods.map(function (method) {
    _extendsApp(conf, method);
  })
  //另外增強擴充套件埋點上送的方法
  conf.william = {
    addActionData: function (ops) {
      console.log('addActionData');
    },
    addVisitLog: function (ops) {
      console.log('addVisitLog');
    }
  }
  return originalApp(conf);
}
//Page及Component物件類似App的處理即可

  至此,整個小程式的生命週期都在掌握之中了,可以按需採集對應的資料,並且對於開發人員來講,還不需要去修改及調整程式碼,鬆耦合埋點方案搞定。

3.增強擴充套件+訂閱/釋出

  上面的實現方案雖然實現了鬆耦合,但是個人覺得還不夠完美,埋點的動作必須要寫在增加的方法裡面,這樣子可維護性較差,也不夠靈活。解耦這事現在對我來說信手拈來,祭出了我的EventHub(基於訂閱/釋出模式實現的訊息匯流排),完美。

//引用EventHub
import EventHub from '../../utils/eventhub.min';
//先把原生的三個物件儲存起來
const originalApp = App,
      originalPage = Page,
      originalComponent = Component;
//在原生的事件函式裡面,新增資料埋點,並替換成新的事件函式
const _extendsApp = function (conf, method) {
  const _o_method = conf[method];
  conf[method] = function (ops) {
    //在此處進行資料埋點
    //此處改成訊息釋出
    if (typeof EventHub != "undefined") {
      EventHub.emit('app' + method, ops);
    }
    if (typeof _o_method === 'function') {
      _o_method.call(this, ops);
    }
  }
}

//重新定義App這個物件,將原來的App物件覆蓋
App = function(conf){
  //定義需要增強的方法
  const methods = ['onLaunch', 'onShow', 'onHide', 'onError']

  methods.map(function (method) {
    _extendsApp(conf, method);
  })
  //另外增強擴充套件埋點上送的方法
  conf.william = {
    addActionData: function (ops) {
      console.log('addActionData');
    },
    addVisitLog: function (ops) {
      console.log('addVisitLog');
    }
  }
  return originalApp(conf);
}
//Page及Component物件類似App的處理即可

  這樣子就可以把埋點處理的邏輯抽離到另外一個JS檔案中去實現。

EventHub.on('apponLaunch',function(ops){
    //在這裡可以處理資料埋點的事
})

延展性思考

  基於上述的實現方案,我們除了增強生命週期,也可以像上面那樣去增加公用的方法,例如App.william.addActionData,更可以通過增強setData方法來進行資料溯源或者進行差量比較來提升效能等方式。


作者:飆豬狂
連結:https://www.jianshu.com/p/3253a15707fc

關於Fundebug

Fundebug專注於JavaScript、微信小程式、微信小遊戲、支付寶小程式、React Native、Node.js和Java實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了9億+錯誤事件,得到了Google、360、金山軟體、百姓網等眾多知名使用者的認可。歡迎免費試用!