Keepalive em vue2 limpa manualmente a memória e há um problema de que a memória de sub-roteamento não pode ser recuperada

causa

Recentemente, os clientes costumam relatar o problema de travamentos do sistema, principalmente à tarde. Após o autoteste, descobri que a memória do sistema não é recuperada após o fechamento da guia. Já lidei com isso. Depois que a guia é fechada, manualmente limpe o keep-alive Não deve haver vazamentos de memória no cache interno. Parece que existem outros caches que não foram limpos.

problema de posicionamento

1. Restaurando a cena

O projeto da empresa é um aplicativo de página única e todas as operações são realizadas em uma guia do navegador. A página inteira é organizada por meio de Layou + sub-roteamento. O nível de roteamento atinge o nível 4 e o negócio é complexo e pesado. Necessidade de reconstruir uma cena de restauração de projeto puro

2. Escreva uma demonstração

Crie um projeto usando vue-cli, [email protected],[email protected]

main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false

new Vue({render: h => h(App),router
}).$mount('#app') 

app.vue

<template><router-view></router-view>
</template>

<script> export default {name: "App",
}; </script> 

visualizar/Página1、visualizar/Página2、visualizar/A1、visualizar/A2

<template><div>Page1<router-view></router-view></div>
</template>

<script> export default {name: "Page1",
}; </script>

<template><div>Page2<router-view></router-view></div>
</template>

<script> export default {name: "Page2",
}; </script>

<template><div>组件view A1</div>
</template>
<script> export default {name: "A1",data() {return {a: new Array(20000000).fill(1), //大概80mb};},
}; </script>

<template><div>组件view A2</div>
</template>
<script> export default {name: "A2",data() {return {a: new Array(20000000).fill(1), //大概80mb};},
}; </script> 

ver/Layout.vue

<template><div><h1>Layout</h1><div class="box"><p>二级路由</p><router-link :to="{ name: 'A' }">A</router-link><br /><router-link :to="{ name: 'B' }">B</router-link></div><div class="box"><p>三级路由</p><router-link :to="{ name: 'AA' }">Page1</router-link><br /><router-link :to="{ name: 'BB' }">Page2</router-link></div><div class="box"><button @click="includeRemove()">清理keepalive缓存</button><br /><router-link to="/home">Home</router-link><br /></div><h1>keep-alive</h1>缓存页面:{
   
   { include }}<keep-alive :include="include"><router-view ref="alive"></router-view></keep-alive></div>
</template>

<script> export default {name: "Layout",data() {return {include: [],};},watch: {'$route'(val) {const name = val.meta.nameif (name && !this.include.includes(name)) {this.include.push(name);}}},methods: {includeRemove() {this.include = [];},},mounted() {},
}; </script>
<style> .box {margin-bottom: 20px;
} </style> 

router/index.js

import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)

const router = new Router({mode: "hash",routes: [{path: "/",redirect: "/home",component: () => import("../view/Layout.vue"),children: [{path: "home",component: () => import("../view/Home.vue"),},],},{path: "/a",component: () => import("../view/Layout.vue"),children: [{path: "a",name: "A",meta: {name: 'A1'},component: () => import("../view/A1.vue"),},],},{path: "/b",component: () => import("../view/Layout.vue"),children: [{path: "b",name: "B",meta: {name: 'A2'},component: () => import("../view/A2.vue"),},],},{path: "/a",component: () => import("../view/Layout.vue"),children: [{path: "page1",name: "Page1",component: () => import("../view/Page1.vue"),children: [{path: "a",name: "AA",meta: {name: 'Page1'},component: () => import("../view/A1.vue"),},],},],},{path: "/b",component: () => import("../view/Layout.vue"),children: [{path: "page2",name: "Page2",component: () => import("../view/Page2.vue"),children: [{path: "b",name: "BB",meta: {name: 'Page2'},component: () => import("../view/A2.vue"),},],},],},],
});

export defaultrouter 

resultado em execução

3. Reproduza o problema

Pode-se ver que, no caso inicial, o uso de memória é de cerca de 7,7 MB

1. Depois de clicar em A e B, a memória ocupa 168 MB

2. Clique em Home para garantir que o roteamento não ocupe os componentes A e B ao limpar o cache e clique novamente para limpar o cache Keepalive

Após GC manual, constatou-se que o uso de memória havia mudado para 7,9 MB, indicando que os componentes A e B foram liberados com sucesso. Isso simulou a situação da empresa ter apenas roteamento secundário na fase inicial do projeto. o problema de travamento do sistema não existia, o que acabou de ser confirmado aqui.

3. Clique em Page1, Page2, o uso de memória é de 168 MB

4. Clique em Home, clique novamente para limpar o cache Keepalive

Ocorreu um problema neste momento, a memória não foi liberada com sucesso, o problema foi encontrado

4. Análise

Primeiro registre o uso de memória no caso inicial

Abra a página 1 e a página 2, vá para a página inicial, limpe o cache Keepalive e registre o instantâneo da memória atual

Pode ser visto na figura que o componente A1 ainda existe e é referenciado pelo vue-router, e nameMap salva todas as informações de roteamento, então o problema é encontrado

Informações de roteamento no estado inicial

Abra a página1 e a página2, mude para a página inicial e limpe as informações de roteamento após o cache keepalive

Teste outra situação, não mude para Home antes de limpar o cache keepalive, neste caso, a memória pode ser liberada com sucesso.

5. Conclusão

1. Se a guia for fechada na rota atual e, em seguida, o cache keepalive for limpo, a memória pode ser reciclada normalmente.
2. Se a rota inativa for fechada em outras rotas, os componentes de roteamento de segundo nível podem ser reciclados normalmente, e a recuperação de memória das rotas de nível inferior é anormal, supondo que as informações na rota inativa correspondida foram alteradas. Afinal, é um modo singleton, o que faz sentido. Por que é normal que a rota ativa remova o cache?

3. Corrija o problema

1. Ideia

1. Obtenha e feche a relação pai-filho de roteamento da guia atual
2. Através de todas as informações de roteamento, percorra e exclua o instances.defaultvalor do roteamento relacionado

2. Implementação de código específico

includeRemove() {this.include = [];// 为啥vue-router不开放直接获取nameMap的接口 淦const routes = this.$router.getRoutes()const nameMap = new Map()for (let index = 0; index < routes.length; index++) {const r = routes[index];nameMap.set(r.name, r)}// 假设我这边获取到了当前移除的tab页签,具体代码根据具体项目实现const rList = ['AA', 'BB']for (let index = 0; index < rList.length; index++) {const name = rList[index];const r = nameMap.get(name)if (r) r.instances.default = undefined}
} 

Após a modificação do código, repita o processo, o uso da memória é o seguinte e o problema foi resolvido com sucesso

Finalmente

Recentemente, também organizei uma nota de JavaScript e ES, um total de 25 pontos de conhecimento importantes, e expliquei e analisei cada ponto de conhecimento. Ele pode ajudá-lo a dominar rapidamente o conhecimento relevante de JavaScript e ES e melhorar a eficiência do trabalho.



Amigos necessitados, você pode clicar no cartão abaixo para receber e compartilhar gratuitamente

Acho que você gosta

Origin blog.csdn.net/web22050702/article/details/128713589
Recomendado
Clasificación