避免对相同图像进行不必要的 http 请求 - vuejs
Posted
技术标签:
【中文标题】避免对相同图像进行不必要的 http 请求 - vuejs【英文标题】:Avoid unnecessary http requests on identical images - vuejs 【发布时间】:2019-04-09 19:32:14 【问题描述】:情况:
在一个页面中,有几个组件接收用户列表。收到列表后,会有一个 foreach 循环调用附加组件来获取用户的图像。多个组件可能包含相同的用户,这意味着重复完全相同的 http 请求以获取“重复图像”。为了避免这些不必要的请求,我在 vueX 的 store 中设置了一个用户有某个 base64 图像的信息,这样我就可以验证我是否已经得到了图像。
问题:当第一个组件请求获取图像并将其保存在商店中时,其余组件已经创建,因此商店仍然是空的,我无法检查是否有图片。
解决方案:创建组件时,我通过使用强制商店存在
this.images[this.user.id] = 'reserved';
但是,我不确定这是否是解决这种情况的正确方法。 接受的建议:'D
代码:
父组件
<template>
<div class="info-cards">
<div class="info-users">
<div class="info-label"> $t('global.users') </div>
<div class="info-images" v-if="users.length > 0">
<base-users-image
v-for="user in users"
:key="user.name"
:user="user"
/>
</div>
<div v-else class="message"> $t('global.noUsersRole') </div>
</div>
</div>
</template>
<script>
// import components
const baseUsersImage = () => System.import(/* webpackChunkName: 'usersImage' */ './../../users/baseUsersImage');
export default
props:
users: Array,
packages: Array
,
components:
baseUsersImage: baseUsersImage
,
</script>
图像组件
<template>
<router-link to="user" class="anchor-image">
<img v-if="show" :src="image" : class="image">
<div v-else class="image-default">t</div>
</router-link>
</template>
<script>
// import requests
import requests from './../../../helpers/requests.js';
// import store
import mapGetters, mapActions from 'vuex';
export default
props:
user: Object
,
data()
return
image: '',
show: false
,
created()
if (this.user.avatar) // check if user has avatar
if ( this.images[this.user.id] == null) // check if it already exists in the store
this.images[this.user.id] = 'reserved'; // set as reserved in store
requests.get(this.user.avatar, responseType: 'arraybuffer' ) // faz o pedido a API da image
.then( (response) =>
this.saveImage( id: this.user.id, url: `data:$response.headers['content-type'];base64,$Buffer.from(response.data, 'binary').toString('base64')` );
, error =>
console.log(error);
);
,
methods:
...mapActions(
saveImage: 'saveImage'
)
,
computed:
...mapGetters(
images: 'images'
)
,
watch:
images:
immediate: true,
deep: true, // so it detects changes to properties only
handler(newVal, oldVal)
if ( newVal[this.user.id] !=='reserved'
&& this.user.avatar
&& newVal[this.user.id] !== undefined
)
this.image = newVal[this.user.id];
this.show = true;
</script>
商店
const state =
images:
const SAVE_IMAGE = (state, payload) =>
state.images =
...state.images,
[payload.id] : payload.url
const saveImage = (commit, payload) =>
commit('SAVE_IMAGE', payload);
【问题讨论】:
【参考方案1】:我会这样做:
首先,我会将所有请求逻辑移至 VueX 并让我的组件尽可能简单。应该可以通过这段代码实现:
export default
props:
user: Object
,
created ()
if (this.user.avatar)
this.$store.dispatch('fetchImage', this.user.avatar)
然后,我会使用这个简单的模式来组织我的商店。首先,我们来看看状态应该是怎样的:
images:
'/users/1/avatar': 'data:png:base64,....', // An image that have been loaded
'/users/2/avatar': null // An image that is supposed to be loading
如您所见,images
对象使用图像 url 作为键,使用 base64 数据作为值。如果data的值为null,则表示图片已经在加载中。
现在让我们看看我们如何编写动作来处理它:
const actions =
fetchImage (state, commit, url)
if (typeof state.images[url] !== 'undefined')
return null
commit('setImage',
url,
payload: null
)
return requests.get(url, responseType: 'arraybuffer').then(response =>
commit('setImage',
url,
payload: `data:$response.headers['content-type'];base64,$Buffer.from(response.data, 'binary').toString('base64')`
)
)
看第一个条件。如果商店中的图片不是undefined
,我们就什么也不做。因为如果图片不是undefined
,则说明要么是null
(正在加载)要么是有值并被加载。
在这个条件之后,我们将图片设置为null
,以防止其他组件加载图片。
最后我们加载图像的内容,并将其提交到状态。
现在让我们看一下模板:
<template>
<router-link to="user" class="anchor-image">
<img v-if="$store.state.images[user.avatar]" :src="$store.state.images[user.avatar]" : class="image">
<div v-else class="image-default">t</div>
</router-link>
</template>
为了检查您是否应该显示图像,您只需使用v-if="$store.state.images[user.avatar]"
。图片一加载就会显示出来。
即使图像是loading
,$store.state.images[user.avatar]
也会是虚假的(它具有 null
值。
希望对你有帮助!
(这是完整的商店:)
const store =
state:
images:
,
mutations:
setImage (state, image)
Vue.set(state.images, image.url, image.payload)
,
actions:
fetchImage (state, commit, url)
if (state.images[url] !== undefined)
return null
commit('setImage',
url,
payload: null
)
return requests.get(url, responseType: 'arraybuffer').then(response =>
commit('setImage',
url,
payload: `data:$response.headers['content-type'];base64,$Buffer.from(response.data, 'binary').toString('base64')`
)
)
【讨论】:
谢谢,这就是我想要的:D以上是关于避免对相同图像进行不必要的 http 请求 - vuejs的主要内容,如果未能解决你的问题,请参考以下文章