避免对相同图像进行不必要的 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的主要内容,如果未能解决你的问题,请参考以下文章

前端性能优化策略

基于MATLAB的均值滤波算法实现

CSS,JS和图像的最小化技术,以避免对服务器的多个请求

使用 AFNetworking 避免重复的 HTTP 请求

Glide系列之缓存策略

AJAX-XMLHttpRequest和本地文件