Использование es6 async / await, map и fetch
Наша цель:
<icon src=”plus.svg” />
Таким образом, он отображается в DOM как
<span class=”icon”><svg>….</svg></span>
Сначала мы создаем icon.vue
компонент:
<template> <span class="icon"></span> </template> <script> export default { props: { src: { type: String, required: true } } }; </script>
Мы загрузим svg в mounted
, где будет просто fetch
значок. С синтаксисом async/await
это довольно просто.
async mounted(){ let svg = await fetch(this.src).then(r => r.text()); this.$el.innerHTML = svg; }
Но когда компонент используется несколько раз, он генерирует несколько запросов к одному и тому же файлу.
<div v-for="item in list"> {{item.desp}} <button @click="add(item)"> <icon src="plus.svg"/> </button> </div> <!-- it will make as many requests as the list length to plus.svg! -->
Итак, нам нужно реализовать некоторый кеш. Мы можем сделать это через Map
let cache = new Map(); async mounted(){ if(!cache.has(this.src)){ cache.set(this.src, await fetch(this.src).then(r => t.text())) } this.$el.innerHTML = cache.get(this.src); }
У нас все хорошо? Нет. Мы обнаружили, что при первой загрузке он по-прежнему выполняет несколько запросов. Проблема в том, что cache
еще не заполнен, поэтому последующий запрос все равно будет выполнен. Мы должны сохранить Promise
в кеше и позволить всем запросам того же src
обращаться к нему.
async mounted(){ if(!cache.has(this.src)){ cache.set(this.src, fetch(this.src).then(r => t.text())) } this.$el.innerHTML = await cache.get(this.src); }
Добавляем некоторую обработку ошибок:
async mounted(){ if(!cache.has(this.src)){ try{ cache.set(this.src, fetch(this.src).then(r => t.text())); } catch (e) { cache.delete(this.src); } } if(cache.has(this.src)){ this.$el.innerHTML = await cache.get(this.src); } }
Полный код компонента:
<template> <span class="icon"></span> </template> <script> let cache = new Map(); export default { props: { src: { type: String, required: true } }, async mounted() { if (!cache.has(this.src)) { try { cache.set(this.src, fetch(this.src).then(r => r.text())); } catch (e) { cache.delete(this.src); } } if (cache.has(this.src)) { this.$el.innerHTML = await cache.get(this.src); } } }; </script>
Не забудьте также упаковать свои файлы svg в конфигурацию веб-пакета.