用vue設計一個數(shù)據(jù)采集器
場景
在業(yè)務上現(xiàn)在有一個場景,當發(fā)生業(yè)務行為變化時,需要對各個模塊的行為進行數(shù)據(jù)收集,數(shù)據(jù)用途可以用作回顧,也可以是例如監(jiān)控這樣的場景。
核心問題
說白了這個需求就是需要對各個模塊狀態(tài)變更進行記錄,然后再格式化上傳到服務端。
解題思路有兩種一種是狀態(tài)監(jiān)聽,第二主動收集。
狀態(tài)監(jiān)聽
狀態(tài)監(jiān)聽優(yōu)勢
快速實現(xiàn)利用狀態(tài)管理和wacth的機制很快就知道不同模塊的狀態(tài)變更,然后就可以獲取數(shù)據(jù),再格式化數(shù)據(jù),發(fā)送給服務端
狀態(tài)監(jiān)聽劣勢
- wacth的重復監(jiān)聽,只要使用了wacth,不管是不是你所需要的數(shù)據(jù),只要狀態(tài)變更就會觸發(fā)改變,監(jiān)聽行為
- 重復依賴,比如說全局有個開始結(jié)束的狀態(tài),在使用wacth的時候就需要在不同的wacth中都去判斷這個狀態(tài),或者有全局的時間模塊等等
- 重復書寫,在不同的監(jiān)聽中需要實踐相同的數(shù)據(jù)格式化方法
- 數(shù)據(jù)分布混亂,雖然控制了全局使用同一管道上傳,但是對于同一個管道內(nèi)的數(shù)據(jù)想做合并去重,或者其他自定義的操作,在不同類型數(shù)據(jù),同一管道的這個場景下面支持很弱
- 場景區(qū)分困難,正常流程觸發(fā)的監(jiān)聽是沒有問題,如果是異常場景觸發(fā)恢復的監(jiān)聽就會導致判斷的復雜性
- 描述的還是比較抽象看下代碼示例
function useA(){ wacth(new,old){ if(start){ if(new.type =='need') const a = { a:new.a } const aa = { aa:new.aa } upload(a) upload(aa) } } } // 多處數(shù)據(jù)散落 function useB(){ // 重復監(jiān)聽 wacth(new,old){ // 全局判斷 if(start){ // 不同狀態(tài)判斷 if(new.type =='need') const b = { b:new.b } //重復數(shù)據(jù)格式 const aa = { b:new.aa } upload(b) upload(aa) } } }
重構(gòu)實現(xiàn)思路
- 依賴收集(監(jiān)聽者模式)
- 狀態(tài)統(tǒng)一
- 數(shù)據(jù)自治(策略模式)
依賴收集
- 核心思想:希望使用同一個采集器解決整個業(yè)務流程,數(shù)據(jù)變更在各個變更方,通過采集器提供的標準的格式化方法去處理數(shù)據(jù),再把數(shù)據(jù)傳遞到采集器,采集器收到數(shù)據(jù)后根據(jù)不同的數(shù)據(jù)格式插入到不同的緩存通道,緩存通道緩存成功,通知業(yè)務處理的監(jiān)聽者,根據(jù)不同的數(shù)據(jù)類型進行不同的處理方式,最后發(fā)送到服務端。
- 具體代碼如下
/* * @Description: 采集公共類 * @version: 1.0.0 * @Author: 吳文周 * @Date: 2021-04-20 19:44:35 * @LastEditors: 吳文周 * @LastEditTime: 2021-04-22 15:20:50 */ /** * @name: Dep * @msg: 依賴收集對象 */ class Dep { private subs: any = [] // 添加觀察者 public addSub(sub: any) { if (sub && sub.update) { this.subs.push(sub) } } // 發(fā)送通知 public notify(content: any) { this.subs.forEach((sub: any) => { sub.update(content) }) } } /** * @name: Watcher * @msg: 觀察者對象 */ class Watcher { private cb!: (arg: any) => void constructor(cb: (arg: any) => void) { // 回調(diào)函數(shù)負責更新 this.cb = cb } // 當數(shù)據(jù)發(fā)生變化的時候更新 update(content: any) { this.cb(content) } } /** * @name: Channel * @msg: 緩存消息管道 */ class Channel { // 管道存儲數(shù)組 private queue: any = [] // 管道大小 private limitSize = 1 // 管道名稱 public name: string constructor(name: string, limitSize = 1) { this.name = name // 最小尺寸是1 limitSize = limitSize >= 1 ? limitSize : 1 this.limitSize = limitSize } /** * @name: push * @msg: 添加的數(shù)據(jù) */ push(item: any) { // 如果超出限制尺寸移除第一個 if (this.limitSize == this.queue.length) { this.queue.shift() } this.queue.push(item) } /** * @name: getLast * @msg: 獲取最后添加的數(shù)據(jù) */ getLast() { if (this.queue.length > 0) { return this.queue[this.queue.length - 1] } else { throw new Error('no item return') } } /** * @name: getLastIndex * @msg: 獲取最后倒數(shù)的數(shù)據(jù) */ getLastIndex(index: number) { try { return this.queue[this.queue.length - index - 1] } catch (error) { throw new Error('no item return') } } /** * @name: isEmpty * @msg: 管道是否為空 */ isEmpty() { return this.queue.length == 0 } } export class Collection { // 依賴收集對象 private dep = new Dep() // 各個數(shù)據(jù)頻道分類 private dataQueue = ['A', 'B', 'C'] // 頻道集合 private channelMap = new Map() // 上傳隊列 private MQ!: LiveCollectionMQ // 策略模式:數(shù)據(jù)類型不同對應不同的處理機制 private strategies = { A: () => { // 可以在不同的管道中獲取相對應的數(shù)據(jù)進行不同邏輯的處理 }, B: () => { }, C: () => { }, } as Record<NotifyType, any> constructor() { this.init() } private init() { // 初始化watcher this.intWatcher() // 初始化頻道 this.initChannel() // 初始化數(shù)據(jù) this.initData() // 初始化隊列 this.initMQ() } /** * @name:intWatcher * @msg:初始化監(jiān)聽器 */ private intWatcher() { this.dep.addSub( new Watcher((type: NotifyType) => { const handlerBack = this.getHandler(type) handlerBack() }), ) } /** * @name: initChannel * @msg: 初始化頻道 */ private initChannel() { this.dataQueue.forEach(item => { this.channelMap.set(item, new Channel(item, 3)) }) } /** * @name: initData * @msg: 初始化頻道數(shù)據(jù) * @param {*} */ private initData() { } /** * @name: initMQ * @msg: 初始化上傳隊列 */ private initMQ() { } /** * @name: getMQ * @msg:獲取消息隊列 */ public getMQ() { return this.MQ } /** * @name:getChannel * @msg:根據(jù)頻道名稱獲取頻道實例 * @param {name}頻道名稱 */ private getChannel(name: NotifyType) { if (this.channelMap.get(name)) { return this.channelMap.get(name) } else { throw new Error('no channel') } } /** * @name:notify * @msg:依賴通知方法 * @param {NotifyType} type * @param {any} mes */ public notify(type: NotifyType, mes: any) { // 設置管道緩存 this.setChannel(type, mes) // 全局統(tǒng)一判斷狀態(tài)判斷是否要分發(fā)數(shù)據(jù) if (state.value.type) { this.dep.notify(type) } } /** * @name: setChannel * @msg: 設置頻道緩存 * @param {NotifyType} name * @param {any} mes */ private setChannel(name: NotifyType, mes: any) { const channel = this.getChannel(name) channel.push(mes) } /** * @name:getHandler * @msg: 獲取 * @param {NotifyType} name */ private getHandler(name: NotifyType) { return this.strategies[name] } /** * @name: getChannelLast * @msg: 獲取指定管道中的最新的數(shù)據(jù) * @param {NotifyType} name * @return {*} */ public getChannelLast(name: NotifyType) { try { const channel = this.getChannel(name) return channel.getLast() } catch (error) { throw new Error(error) } } /** * @name: getChannelLast * @msg: 獲取指定管道中的倒序數(shù)據(jù) * @param {NotifyType} name * @param {number} index */ public getChannelItemByLastIndex(name: NotifyType, index: number) { try { const channel = this.getChannel(name) return channel.getLastIndex(index) } catch (error) { throw new Error(error) } } /** * @name: generateA * @msg: 生成A數(shù)據(jù)方法 */ public generateA() { } /** * @name: generateB * @msg: 生成B數(shù)據(jù)方法 */ public generateB() { } /** * @name: generateC * @msg: 生成C數(shù)據(jù)方法 */ public generateC() { } } export const CollectionHelper = new Collection()
總結(jié)
- 我覺得去了解一個框架的一個好的思路就是在運用它的核心原理去解決一個原理,正如之前使用webpack的插件機制一樣,這次使用的是vue的依賴收集
- 狀態(tài)自治,職責統(tǒng)一是個代碼封裝的好習慣
以上就是用vue設計一個數(shù)據(jù)采集器的詳細內(nèi)容,更多關(guān)于vue 設計數(shù)據(jù)采集器的資料請關(guān)注腳本之家其它相關(guān)文章!
- Vue2.0/3.0雙向數(shù)據(jù)綁定的實現(xiàn)原理詳解
- 關(guān)于vuex強刷數(shù)據(jù)丟失問題解析
- Vue 如何追蹤數(shù)據(jù)變化
- vue+canvas實現(xiàn)數(shù)據(jù)實時從上到下刷新瀑布圖效果(類似QT的)
- vue 數(shù)據(jù)(data)賦值問題的解決方案
- Vue 重置data的數(shù)據(jù)為初始狀態(tài)操作
- Vue組件傳值過程中丟失數(shù)據(jù)的分析與解決方案
- SpringBoot+Vue實現(xiàn)數(shù)據(jù)添加功能
- 手寫Vue2.0 數(shù)據(jù)劫持的示例
- vue 數(shù)據(jù)雙向綁定的實現(xiàn)方法
- Vue中避免濫用this去讀取data中數(shù)據(jù)
相關(guān)文章
vue 實現(xiàn)v-for循環(huán)回來的數(shù)據(jù)動態(tài)綁定id
今天小編就為大家分享一篇vue 實現(xiàn)v-for循環(huán)回來的數(shù)據(jù)動態(tài)綁定id,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11element-ui+vue-treeselect下拉框的校驗過程
這篇文章主要介紹了element-ui+vue-treeselect下拉框的校驗過程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07Vue中使用v-model雙向數(shù)據(jù)綁定select、checked等多種表單元素的方法
?v-model?指令可以用在表單?input、textarea?及?select?元素上創(chuàng)建雙向數(shù)據(jù)綁定,它會根據(jù)控件類型自動選取正確的方法來更新元素,本文給大家介紹Vue中如何使用v-model雙向數(shù)據(jù)綁定select、checked等多種表單元素,感興趣的朋友一起看看吧2023-10-10