業(yè)務(wù)前端的本質(zhì)--數(shù)據(jù)維護(hù)
共 5202字,需瀏覽 11分鐘
·
2024-07-28 21:51
大廠技術(shù) 高級(jí)前端 Node進(jìn)階
點(diǎn)擊上方 程序員成長(zhǎng)指北,關(guān)注公眾號(hào)
回復(fù)1,加入高級(jí)Node交流群
Vue/React 將前端開發(fā)從 jQuery 命令式的編程風(fēng)格帶到了聲明式的編程風(fēng)格,開發(fā)者只需要描述界面應(yīng)該是什么樣子,Vue/React 就會(huì)根據(jù)數(shù)據(jù)的變化自動(dòng)更新界面。
因此對(duì)于業(yè)務(wù)頁(yè)面只需要關(guān)心數(shù)據(jù)有什么以及引起數(shù)據(jù)的變化有什么。
數(shù)據(jù)
數(shù)據(jù)主要有兩大類,ui 相關(guān)和非 ui 相關(guān)。
ui 相關(guān)
前端本質(zhì)上就是將數(shù)據(jù)可視化,因此定義的變量中一部分就是供頁(yè)面展示使用的,在 Vue 中會(huì)把這些數(shù)據(jù)定義在 data 中變?yōu)轫憫?yīng)式,在 React 中會(huì)調(diào)用 SetState 來更新這些變量以便更新視圖。
前端自閉環(huán)
一些變量?jī)H在前端記錄進(jìn)行 ui 的更新,后端不會(huì)感知到。
比如頁(yè)面的 loading 態(tài):
點(diǎn)擊態(tài),是否打開展示更多:
來自后端
頁(yè)面數(shù)據(jù)是存在數(shù)據(jù)庫(kù)中,后端會(huì)把這些數(shù)據(jù)給前端,供前端展示,這類數(shù)據(jù)又分為兩種:
-
將數(shù)據(jù)直接賦值給某個(gè)前端變量進(jìn)行展示,比如昵稱、標(biāo)題等。 -
將數(shù)據(jù)轉(zhuǎn)換后再進(jìn)行展示,比如錢相關(guān)字段因?yàn)榫葐栴},后端存儲(chǔ)的是分,給到前端以后需要轉(zhuǎn)換成元進(jìn)行展示。
來自底層
設(shè)備信息:通過屏幕寬高來設(shè)置彈窗的寬高。
localStorage:一些模塊可能一天只需要展示一次,前端將標(biāo)志存到 localStorage 中自行進(jìn)行判斷。
非 ui 相關(guān)
這些變量和 ui 無關(guān)也不會(huì)和頁(yè)面后端交互,舉幾個(gè)例子:
前端自閉環(huán)
請(qǐng)求鎖:一些提交請(qǐng)求,為了防止用戶多次提交,可以在接口請(qǐng)求前設(shè)置一個(gè)標(biāo)志位,類似于下邊這樣。
// 用于保存請(qǐng)求狀態(tài)的標(biāo)志位
let isSubmitting = false;
// 模擬一個(gè)異步請(qǐng)求
function sendRequest() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("請(qǐng)求成功");
}, 2000); // 模擬2秒的請(qǐng)求時(shí)間
});
}
// 處理按鈕點(diǎn)擊事件
function handleSubmit() {
// 檢查標(biāo)志位
if (isSubmitting) {
console.log("請(qǐng)求正在進(jìn)行中,請(qǐng)稍后...");
return;
}
// 設(shè)置標(biāo)志位
isSubmitting = true;
console.log("開始請(qǐng)求...");
// 發(fā)送請(qǐng)求
sendRequest().then(response => {
console.log(response);
}).catch(error => {
console.error(error);
}).finally(() => {
// 請(qǐng)求完成后重置標(biāo)志位
isSubmitting = false;
console.log("請(qǐng)求完成,可以再次提交");
});
}
埋點(diǎn)數(shù)據(jù):模塊曝光或者用戶點(diǎn)擊的時(shí)候進(jìn)行埋點(diǎn),相關(guān)數(shù)據(jù)會(huì)提前存到一個(gè)對(duì)象中。
定時(shí)器引用:頁(yè)面中創(chuàng)建定時(shí)器后用一個(gè)變量保存定時(shí)器實(shí)例,用戶可能離開頁(yè)面的時(shí)候還未執(zhí)行到定時(shí)器,因此需要在離開頁(yè)面的時(shí)候進(jìn)行清除。
Page({
data: {
// 其他數(shù)據(jù)
},
// 用于保存定時(shí)器實(shí)例的變量
timer: null,
// 頁(yè)面加載時(shí)創(chuàng)建定時(shí)器
onLoad: function() {
this.createTimer();
},
// 創(chuàng)建定時(shí)器的方法
createTimer: function() {
this.timer = setTimeout(() => {
console.log('定時(shí)器執(zhí)行中...');
}, 5000); // 5秒后執(zhí)行
},
// 頁(yè)面卸載時(shí)清除定時(shí)器
onUnload: function() {
this.clearTimer();
},
// 清除定時(shí)器的方法
clearTimer: function() {
if (this.timer) {
clearTimeout(this.timer);
console.log('頁(yè)面即將卸載,定時(shí)器已清除');
}
},
// 其他頁(yè)面方法和事件處理函數(shù)
});
來自后端
埋點(diǎn)數(shù)據(jù):模塊曝光或者用戶點(diǎn)擊的時(shí)候進(jìn)行埋點(diǎn),一些數(shù)據(jù)會(huì)由后端給到。
來自底層
localStorage:比如存儲(chǔ)用戶的點(diǎn)擊次數(shù),進(jìn)行相應(yīng)的限頻。
引起數(shù)據(jù)的變化
數(shù)據(jù)變化的根源就是用戶操作,用戶的操作可能直接引起數(shù)據(jù)變化,也可能觸發(fā)某些全局事件或者定時(shí)器,又觸發(fā)新一輪的頁(yè)面數(shù)據(jù)變化。
用戶操作
大部分的數(shù)據(jù)變化都是由于用戶的操作,比如點(diǎn)擊、滑動(dòng)。
根據(jù)點(diǎn)擊的位置不同,可能觸發(fā)不同的動(dòng)作。比如去請(qǐng)求后端接口拿數(shù)據(jù)、進(jìn)入新頁(yè)面、離開當(dāng)前頁(yè)面,在小程序中會(huì)觸發(fā) onHide 、onShow 生命周期,在這些周期中會(huì)做一些動(dòng)作更新數(shù)據(jù)。
還有經(jīng)常遇到的表單逆向操作,當(dāng)用戶依次填了 A 項(xiàng)、B 項(xiàng)、C 項(xiàng),由于 B、C 依賴于 A 項(xiàng)的選擇,當(dāng)用戶再修改 A 項(xiàng)的時(shí)候需要清空 B、C 之前的選擇。
監(jiān)聽數(shù)據(jù)變化
在 Vue 中通過 watch 監(jiān)聽變量,在 React 中通過 useEffect 監(jiān)聽變量。一般情況監(jiān)聽的是組件的 prop,當(dāng)父組件變化時(shí),子組件進(jìn)行相應(yīng)的更新。
定時(shí)器
定時(shí)器時(shí)間結(jié)束后,會(huì)觸發(fā)定時(shí)器注冊(cè)的回調(diào)函數(shù)。
常用于頁(yè)面上的倒計(jì)時(shí)的更新。也用于解決 ui 更新的時(shí)序問題,直接給 setTimeout 事件設(shè)置為 0,讓回調(diào)函數(shù)到下一個(gè)宏任務(wù)周期去執(zhí)行。
全局事件
主要用于跨模塊之間的通信,常用的比如 eventbus、vuex、redux 等。
常見的比如全局的登錄事件,各個(gè)頁(yè)面需要監(jiān)聽登錄成功才去觸發(fā)后續(xù)的業(yè)務(wù)邏輯。
關(guān)聯(lián)
理想狀態(tài),用戶動(dòng)作 => 更新數(shù)據(jù) => 頁(yè)面自動(dòng)更新。
但實(shí)際上,當(dāng)數(shù)據(jù)變化的時(shí)候,由于全局事件、定時(shí)器的存在,還會(huì)繼續(xù)觸發(fā)新一輪的數(shù)據(jù)更新。
此外,數(shù)據(jù)變化每次也不止變更一個(gè)數(shù)據(jù),數(shù)據(jù)之間又會(huì)有相應(yīng)的聯(lián)動(dòng)關(guān)系。
這也是為什么框架都在倡導(dǎo)單一數(shù)據(jù)流的原因,全局事件第一個(gè)人用起來會(huì)很方便,但在一個(gè)上百人的前端項(xiàng)目中,后續(xù)頁(yè)面繼續(xù)迭代或者重構(gòu)的時(shí)候,漏改或者影響面評(píng)估錯(cuò)誤的風(fēng)險(xiǎn)也會(huì)增高。
當(dāng)增加一個(gè)數(shù)據(jù)變量的時(shí)候也要考慮清楚,是否有必要新增,因?yàn)槊吭鲆粋€(gè)都會(huì)增加頁(yè)面的內(nèi)部復(fù)雜度。當(dāng)然有時(shí)候也不是變量越少越好,當(dāng)各個(gè)地方共用一個(gè)變量,也意味著這個(gè)變量賦予了多重含義,有悖「單一職責(zé)」。
總
業(yè)務(wù)前端看起來簡(jiǎn)單,就是維護(hù)一些數(shù)據(jù)。但當(dāng)頁(yè)面數(shù)據(jù)變量越來越多,交互越來越多,數(shù)據(jù)更新會(huì)變得錯(cuò)綜復(fù)雜,后續(xù)迭代的心智負(fù)擔(dān)會(huì)越來越重。
此時(shí)能做的就是明確當(dāng)前數(shù)據(jù)(ui/非 ui 數(shù)據(jù))有什么,引起數(shù)據(jù)的變化有什么(用戶動(dòng)作、數(shù)據(jù)之間的關(guān)聯(lián)等),這些理清之后出現(xiàn) bug 的概率也會(huì)極大降低。
最根本的還是降低函數(shù)和函數(shù)之間、模塊與模塊之間的依賴關(guān)系,也就是常說的高內(nèi)聚、低耦合,保證后續(xù)改動(dòng)的影響面足夠小且明確。
最終看到的頁(yè)面不再是頁(yè)面,而是數(shù)據(jù)的變化和流動(dòng)。
Node 社群
我組建了一個(gè)氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對(duì)Node.js學(xué)習(xí)感興趣的話(后續(xù)有計(jì)劃也可以),我們可以一起進(jìn)行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。
“分享、點(diǎn)贊、在看” 支持一波??
