用vue設(shè)計一個數(shù)據(jù)采集器
場景
在業(yè)務(wù)上現(xiàn)在有一個場景,當(dāng)發(fā)生業(yè)務(wù)行為變化時,需要對各個模塊的行為進(jìn)行數(shù)據(jù)收集,數(shù)據(jù)用途可以用作回顧,也可以是例如監(jiān)控這樣的場景。
核心問題
說白了這個需求就是需要對各個模塊狀態(tài)變更進(jìn)行記錄,然后再格式化上傳到服務(wù)端。
解題思路有兩種一種是狀態(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ā)送給服務(wù)端
狀態(tài)監(jiān)聽劣勢
- wacth的重復(fù)監(jiān)聽,只要使用了wacth,不管是不是你所需要的數(shù)據(jù),只要狀態(tài)變更就會觸發(fā)改變,監(jiān)聽行為
- 重復(fù)依賴,比如說全局有個開始結(jié)束的狀態(tài),在使用wacth的時候就需要在不同的wacth中都去判斷這個狀態(tài),或者有全局的時間模塊等等
- 重復(fù)書寫,在不同的監(jiān)聽中需要實踐相同的數(shù)據(jù)格式化方法
- 數(shù)據(jù)分布混亂,雖然控制了全局使用同一管道上傳,但是對于同一個管道內(nèi)的數(shù)據(jù)想做合并去重,或者其他自定義的操作,在不同類型數(shù)據(jù),同一管道的這個場景下面支持很弱
- 場景區(qū)分困難,正常流程觸發(fā)的監(jiān)聽是沒有問題,如果是異常場景觸發(fā)恢復(fù)的監(jiān)聽就會導(dǎo)致判斷的復(fù)雜性
- 描述的還是比較抽象看下代碼示例
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(){
// 重復(fù)監(jiān)聽
wacth(new,old){
// 全局判斷
if(start){
// 不同狀態(tài)判斷
if(new.type =='need')
const b = {
b:new.b
}
//重復(fù)數(shù)據(jù)格式
const aa = {
b:new.aa
}
upload(b)
upload(aa)
}
}
}
重構(gòu)實現(xiàn)思路
- 依賴收集(監(jiān)聽者模式)
- 狀態(tài)統(tǒng)一
- 數(shù)據(jù)自治(策略模式)
依賴收集
- 核心思想:希望使用同一個采集器解決整個業(yè)務(wù)流程,數(shù)據(jù)變更在各個變更方,通過采集器提供的標(biāo)準(zhǔn)的格式化方法去處理數(shù)據(jù),再把數(shù)據(jù)傳遞到采集器,采集器收到數(shù)據(jù)后根據(jù)不同的數(shù)據(jù)格式插入到不同的緩存通道,緩存通道緩存成功,通知業(yè)務(wù)處理的監(jiān)聽者,根據(jù)不同的數(shù)據(jù)類型進(jìn)行不同的處理方式,最后發(fā)送到服務(wù)端。
- 具體代碼如下
/*
* @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ù)負(fù)責(zé)更新
this.cb = cb
}
// 當(dāng)數(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ù)類型不同對應(yīng)不同的處理機制
private strategies = {
A: () => {
// 可以在不同的管道中獲取相對應(yīng)的數(shù)據(jù)進(jìn)行不同邏輯的處理
},
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) {
// 設(shè)置管道緩存
this.setChannel(type, mes)
// 全局統(tǒng)一判斷狀態(tài)判斷是否要分發(fā)數(shù)據(jù)
if (state.value.type) {
this.dep.notify(type)
}
}
/**
* @name: setChannel
* @msg: 設(shè)置頻道緩存
* @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)自治,職責(zé)統(tǒng)一是個代碼封裝的好習(xí)慣
以上就是用vue設(shè)計一個數(shù)據(jù)采集器的詳細(xì)內(nèi)容,更多關(guān)于vue 設(shè)計數(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)CLI 3.0 + momentjs + lodash打包時優(yōu)化
今天小編就為大家分享一篇Vue 實現(xiàn)CLI 3.0 + momentjs + lodash打包時優(yōu)化,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11
解決vue單頁路由跳轉(zhuǎn)后scrollTop的問題
今天小編就為大家分享一篇解決vue單頁路由跳轉(zhuǎn)后scrollTop的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-09-09
VUE3刷新頁面報錯問題解決:Uncaught?SyntaxError:Unexpected?token?&apo
這篇文章主要介紹了VUE3刷新頁面報錯:Uncaught?SyntaxError:?Unexpected?token?‘<‘,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03
從Vue轉(zhuǎn)換看Webpack與Vite 代碼轉(zhuǎn)換機制差異詳解
這篇文章主要為大家介紹了從Vue轉(zhuǎn)換看Webpack與Vite代碼轉(zhuǎn)換機制差異詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10

