Promise.all封装图片预加载

691 阅读1分钟

背景

渲染图片资源时,资源过多过大,空白期会过长;如果希望马上呈现,而不是慢慢加载,就要用到图片预加载

原理,是利用浏览器缓存机制:访问同一张地址的图片,只请求图片一次。将这个请求的时机提前,把资源提前加载好(如果是首页,也可先放置加载gif,加载资源后切换src), 提前加载的实现,可new Image()去模拟,加载后将image置为null

代码实现

utiljs

/**
 * promise
 * 基本的图片预加载 
 */
/**
 * promise
 * @param {*} url 
 * @returns 
 * 基本的图片预加载 
 */
const imgPreloader = url => {
    return new Promise((resolve, reject) => {
      //新建image对象去加载url
      let temp = new Image();
      temp.src = url
      temp.onload = () => {
        //加载完成 执行resolve
        window.console.log('onload')
        resolve('true');
      };
      temp.onerror = () => {
        window.console.log('onerror')
        reject('false');
      };
      //清除image对象 
      temp=null
    });
}

/**
 * promise.all并行响应
 * @param imgs 图片路径数组
 * @returns {Promise<unknown[]>}
 */
const allImgPreloader = imgs => {
  let promiseArr = new Array()
  imgs.forEach(url => {
    //所有加载promise
    promiseArr.push(imgPreloader(url))
  })
  //执行结果
  return Promise.all(promiseArr)
}

export default allImgPreloader


index.vue

<template>
    <div class="homeView">
        <img v-for="(item, index) in imgs" :src="item" alt="" :key="index"> </div>
</template>

<script>
//引入子组件

import allImgPreloader from './preloadUtil.js'
export default {
    name: "HomeView",
    //注册子组件
    components: {

    },
    data() {
        return {
            imgs: [ //require相对路径
                require('../../imgs/pic1.png'),
                require('../../imgs/pic2.png'),
                require('../../imgs/pic3.png'),
                require('../../imgs/pic4.png'),
                require('../../imgs/pic5.png'),
                require('../../imgs/pic6.png'),
            ]
        }
    },
    created() {
        this.begin()
    },
    methods: {
        /**
         * 异步function 处理onload
         */
        preImg() {
            //调用
            return allImgPreloader(this.imgs)
        },
        async begin() {
            //预加载时展示加载loading
            const toast = this.$toast.loading({
                duration: 0, // 持续展示 toast
                forbidClick: true,
                message: '预加载中...'
            });
            let resultList = await this.preImg()
            window.console.log('list', resultList)
            //promise执行完毕 做后面的逻辑 比如清除loading
            toast.clear()
        }
    }
}
</script>

<style scoped>
.homeView {
    width: 80%;
    height: auto;
    margin: auto;

}

img {
    width: 100px;
    height: 100px;
}
</style>




总结

封装时,new Image加载图片资源,加载后对象置空;封装为promise,多个则放入Promise.all;使用时结合async await,在预加载开始和结束时,做loading的渲染和清除等操作。

仓库地址 github.com/xuhongg/ima…