緩存架構(gòu)
今天所說的緩存是針對于api數(shù)據(jù)的緩存。緩存實(shí)際上有兩個(gè)方面的緩存:
1、api數(shù)據(jù)的緩存
2、資源的緩存:前端的話無需要太多關(guān)心的,因?yàn)閔tml+css+js在沒有設(shè)置特殊請求頭的情況下,瀏覽器是默認(rèn)緩存的
優(yōu)化三字經(jīng):快、小、省
快
1、選擇更快的api
2、算法層面--盡量減少自己的操作步驟
小--說的其實(shí)是請求資源
1、通過webpack壓縮,例如:tree-shaking----(治標(biāo)不治本)
2、盡量不要去寫無用(重復(fù))的代碼----(治本)
從vue3層面談一下快和小
快方面:
1、api方面:vue3把完成響應(yīng)式的方案defineProty轉(zhuǎn)變成proxy
說明
:defineProty
是針對于對象的api,針對于一個(gè)對象的屬性去更改權(quán)限標(biāo)簽,要想將data里面定義的數(shù)據(jù)觸發(fā)響應(yīng)式的,就得為data里面所有的數(shù)據(jù)通過defineProty去定義get和set,必須去for in data去遍歷,如果data的數(shù)據(jù)特別多的話,會非常耗時(shí)的;
proxy
是代理整個(gè)對象,所以沒必要去查找data里面的每個(gè)對象,直接把data代理就好,不需要for...in循環(huán);
proxy是不會改變原對象的,defineProty是改變原對象的
2、算法方面:Diff算法
Diff算法是vue一個(gè)很重要的東西(核心),用來對比新老Dom,從而產(chǎn)生更新;
在vue2里面,每個(gè)dom是逐層逐個(gè)比對的
例如:
<div>
<h1>123</h1>
<p>{{msg}}</p>
</div>
在vue2中,比對順序是,先比對div,然后比對h1,再比對p,實(shí)際上,h1是沒必要去比對的,它永遠(yuǎn)不會改變的,只有寫了vue指令的p會發(fā)生變化的;
在vue3中,會首先分析出那些是綁定了vue指令的(會發(fā)生變化),只會去比對這些綁定了動態(tài)指令的,減少了需要去比對的數(shù)量,從而減少了運(yùn)行/編碼耗時(shí),速度會變快很多;
小方面:
vue3擁抱了tree-shaking
vue2是把所有的屬性(mounted,methods)都是掛載在原型鏈上的,在開發(fā)的過程中,我們實(shí)際上用的api是40%-50%的,但是會把其余沒有用到的api打包到我們的代碼中。
vue3是函數(shù)式編程,我們在打包時(shí),利用webpack的tree-shaking,將我們沒用到的api刪除,不會打包到我們的代碼中,大大減少了打包后的代碼體積。
省方面(減少請求等)
請求緩存思路
注意:
1、緩存架構(gòu)要保障單一性(單一性,就像在vue實(shí)例中,保證只有一個(gè)vuex)
if(!window.mycache){
window.mycache=xxx
}
判斷window上是否已經(jīng)掛載了我們定義的緩存架構(gòu),如果掛載了,將不再去掛載,否則的話就會掛載我們的緩存架構(gòu)。
2、緩存區(qū)域的權(quán)限問題(外界區(qū)域不能操作緩存區(qū)域里面的內(nèi)容)
1>寫在匿名自調(diào)用函數(shù)里面
if(!window.mycache){
window.mycache=(function(){
...
})()
}
2>那怎樣讓其拿到or修改緩存區(qū)域里面的值呢?
為了解決這個(gè)問題,緩存區(qū)域利用閉包的原理;將緩存區(qū)域作為私有變量,存在匿名函數(shù)里面
if(!window.mycache){
window.mycache=(function(){
// 解決怎樣讓其拿到or修改緩存區(qū)域里面的值
var cache = {}
// return一些方法,去拿到or編輯緩存區(qū)域的數(shù)據(jù)
return {
get:function(){},
set:function(){},
....
}
})()
}
if(!window.mycache){
window.mycache=(function(){
// 解決怎樣讓其拿到or修改緩存區(qū)域里面的值
var cache = {}
// return一些方法,去拿到or編輯緩存區(qū)域的數(shù)據(jù)
return {
get:function(api){
// 如果有緩存,我們是個(gè)同步請求,但是如果沒有請求,是個(gè)異步操作,那怎樣解決這種情況呢?如果是異步,我們在接受時(shí)
// 如果這樣寫:
// res = window.mycache.get('api')
// console.log(res) // 異步情況下,res是獲取不到值得,會報(bào)錯,我們將下面代碼寫在pormise中可解決
// if(cache[api]){
// // 同步操作
// return cache[api]
// }else{
// // 異步操作
// this.set(api).then(res=>{
// cache[api] = res
// return res
// })
// }
return new Promise((resolve,reject)=>{
if(cache[api]){
// 同步操作
resolve(cache[api])
}else{
// 異步操作
this.set(api).then(res=>{
cache[api] = res
resolve(res)
})
}
})
///寫成Promise后,我們接受返回結(jié)果時(shí),只需要像下面這樣去接受數(shù)據(jù)
// window.mycache.get('api').then(res)=>{
// todo
// }
},
set:function(api){
},
remove:function(){
}
}
})()
}
3>緩存得問題:
a:緩存更新的問題
如果是本地緩存,像localStorage,cookies等,里面的數(shù)據(jù)不會輕易改變,但是要是變了呢?怎樣更新呢?
方法1):webscoket,但是這種成本太大
方法2):輪詢的方式
像我們上面的例子,緩存是存于內(nèi)存的,v8引擎,64位允許存1.4G,32位允許存700MB,所以要考慮溢出的情況。
if(!window.mycache){
window.mycache=(function(){
// 解決
var cache = {}
var cacheArr = []
// return一些方法,去拿到or編輯緩存區(qū)域的數(shù)據(jù)
return {
get:function(api){
// 如果有緩存,我們是個(gè)同步請求,但是如果沒有請求,是個(gè)異步操作,那怎樣解決這種情況呢?如果是異步,我們在接受時(shí)
// 如果這樣寫:
// res = window.mycache.get('api')
// console.log(res) // 異步情況下,res是獲取不到值得,會報(bào)錯,我們將下面代碼寫在pormise中可解決
// if(cache[api]){
// // 同步操作
// return cache[api]
// }else{
// // 異步操作
// this.set(api).then(res=>{
// cache[api] = res
// return res
// })
// }
return new Promise((resolve,reject)=>{
if(cache[api]){
// 同步操作
resolve(cache[api])
}else{
// 異步操作
this.set(api).then(res=>{
// 解決緩存超出內(nèi)存的問題 start
if(cacheArr.length > 10){
var _api = cacheArr.shift()
this.remove(_api)
}
// 解決緩存超出內(nèi)存的問題 end
cache[api] = res
cacheArr.push(api)
resolve(res)
})
}
})
//寫成Promise后,我們接受返回結(jié)果時(shí),只需要像下面這樣去接受數(shù)據(jù)
// window.mycache.get('api').then(res)=>{
// ...
// }
},
set:function(api){
},
remove:function(){
}
}
})()
}