图片下载本地缓存时间戳显示图片方法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图片下载本地缓存时间戳显示图片方法相关的知识,希望对你有一定的参考价值。

来源:http://ask.dcloud.net.cn/article/511

源码下载 

参考文章
http://ask.dcloud.net.cn/article/256
http://ask.dcloud.net.cn/article/397

说明:为了方便,里面使用的图片来源是从上面文章中的源码项目获取的.
说明:参考了上面文章中的思路,然后自己重新写了一个较为完整的图片本地缓存显示工具.
功能
1.第一次显示图片时下载到本地,然后之后如果本地存在缓存(根据url),则显示本地缓存的图片
2. 基于plus的storage,对每一个图片的缓存进行控制管理,增加时间戳参数,来控制本地缓存的有效时间
3. 将所有的下载任务放入队列中,进行统一下载管理,增加最大并发请求数,防止一次性请求过多损耗性能
4. 加入了图片缓存池机制,对于同一个下载路径的图片不会多次下载,而是填入缓存池,下载后统一回调
5. 修改了图片本地路径的获取方法,摆脱第三方依赖
6. 重构了代码,并入开发框架中

使用方法

* 外部API:注意,需要显示的图片需要有data-img-localcache这个属性(用来放目标url),dom需要是原生对象
 * 清除所有图片缓存:MobileFrame.ImageUtil.ImageLoaderFactory.clearLoaderImgsCache(successCb,errorCb)
 * 采取本地缓存显示所有图片:MobileFrame.ImageUtil.ImageLoaderFactory.setAllNetImgsWithLocalCache();
 * 清除某一张图片的本地缓存:MobileFrame.ImageUtil.ImageLoaderFactory.clearNetUrlImgCache(src);
 * 显示某一张图片:MobileFrame.ImageUtil.ImageLoaderFactory.setImgWidthLocalCache(dom,src);

源码

/**
 * @description   移动开发框架
 * @author dailc  dailc 
 * @version 1.0
 * @time 2016-01-11 16:57:57
 * 功能模块:只依赖于plus系统
 * @see http://ask.dcloud.net.cn/people/%E6%92%92%E7%BD%91%E8%A6%81%E8%A7%81%E9%B1%BC
 * 图片本地缓存模块********************************
 * 1.本地缓存显示图片
 * 2.增加storage,增加每一个本地缓存的有效时间戳
 * 3.增加自定义设置方法,可以根据不同需求,对参数进行修改
 * 4.采用下载队列进行下载管理,增加最大并发请求数,防止一次性请求过多损耗性能
 * 5.修改了图片本地路径的获取方法,摆脱第三方依赖
 * 6.重构代码
 * 外部API:注意,需要显示的图片需要有data-img-localcache这个属性(用来放目标url)
 * 清除所有图片缓存:MobileFrame.ImageUtil.ImageLoaderFactory.clearLoaderImgsCache(successCb,errorCb)
 * 采取本地缓存显示所有图片:MobileFrame.ImageUtil.ImageLoaderFactory.setAllNetImgsWithLocalCache();
 * 清除某一张图片的本地缓存:MobileFrame.ImageUtil.ImageLoaderFactory.clearNetUrlImgCache(src);
 * 显示某一张图片:MobileFrame.ImageUtil.ImageLoaderFactory.setImgWidthLocalCache(dom,src);
 * 图片本地缓存模块完毕********************************
 */
(function(global) {
    /**
     * 定义全局函数对象 define出来的
     */
    var mapping = {};
    /**
     * 缓存,正在用到的对象,函数中return 出来的,这样就不需要重复执行函数
     */
    var cache = {};
    /**
     * @description 模块定义
     * @param {String} id id
     * @param {Function} func 对应的函数对象
     */
    global.define = function(id, func) {
        mapping[id] = func;
    };
    /**
     * @description 生成模块对象,并采用本地缓存
     * @param {String} id
     */
    global.require = function(id) {
        if (!/\\.js$/.test(id)) {
            id += \'.js\';
        }
        if (cache[id]) {
            return cache[id];
        } else {
            return cache[id] = mapping[id]({});
        }
    };
    /**
     * @description 配置全局工具类以及一些需要用到的全局函数
     */
    (function() {
        global.MobileFrame = {};
        /**
         * 空函数
         */
        MobileFrame.noop = function() {};
        /**
         * @description each遍历操作
         * @param {type} elements
         * @param {type} callback
         * @returns {global}
         */
        MobileFrame.each = function(elements, callback, hasOwnProperty) {
            if (!elements) {
                return this;
            }
            if (typeof elements.length === \'number\') {
                [].every.call(elements, function(el, idx) {
                    return callback.call(el, idx, el) !== false;
                });
            } else {
                for (var key in elements) {
                    if (hasOwnProperty) {
                        if (elements.hasOwnProperty(key)) {
                            if (callback.call(elements[key], key, elements[key]) === false) return elements;
                        }
                    } else {
                        if (callback.call(elements[key], key, elements[key]) === false) return elements;
                    }
                }
            }
            return global;
        };
        /**
         * @description plusReady
         * @param {Function} callback
         * @returns {global} 返回的是global
         */
        MobileFrame.plusReady = function(callback) {
            if (window.plus) {
                setTimeout(function() { //解决callback与plusready事件的执行时机问题(典型案例:showWaiting,closeWaiting)
                    callback();
                }, 0);
            } else {
                document.addEventListener("plusready", function() {
                    callback();
                }, false);
            }
            return global;
        };
        /**
         * @description 得到相对路径对应的key,这个key可以使缓存池的或者是本地缓存键值
         * 主要作用是去除非法字符
         * @param {String} relativePath
         */
        MobileFrame.getRelativePathKey = function(relativePath) {
            var finalKey =
                //                  relativePath.replace(\'\\/\', \'\').replace(\'.\', \'\').replace(\'\\/\', \'\')
                //                  .replace(\'_download\', \'\').replace(\'jpg\', \'\');
                relativePath.replace(/[&\\|\\\\\\*^%$#@\\-]/g, "");
            return finalKey;
        };
        /**
         * @description 更改url类型,去除cache,因为cache会造成一些困扰
         * @param {String} url 传入的url
         */
        MobileFrame.changImgUrlTypeNoCache = function(url) {
            url = url || \'\';
            if (url.indexOf(\'?\') != -1) {
                url += \'&timeRandKey=\' + Math.random();
            } else {
                url += \'?timeRandKey=\' + Math.random();
            }
            return url;
        };
        /**
         * @description 删除指定路径的文件
         * @param {String} relativePath  绝对路径或相对路径例如:  _downloads/imgs/test.jpg
         * @param {Function} successCallback  删除成功回调
         * @param {Function} errorCallback  失败回调
         */
        MobileFrame.delFile = function(relativePath, successCallback, errorCallback) {
            if (!relativePath) {
                return;
            }
            MobileFrame.plusReady(function() {
                plus.io.resolveLocalFileSystemURL(relativePath, function(entry) {
                    entry.remove(function(entry) {
                        if (successCallback && typeof(successCallback) == \'function\') {
                            successCallback(true);
                        }
                    }, function(e) {
                        if (errorCallback && typeof(errorCallback) == \'function\') {
                            errorCallback(\'删除文件失败!\');
                        }
                    });
                }, function() {
                    if (errorCallback && typeof(errorCallback) == \'function\') {
                        errorCallback(\'打开文件路径失败!\');
                    }
                });
            });
        };
        /**
         * @description 判断网络状态
         */
        function GetNetWorkState() {
            var NetStateStr = \'未知\';
            var types = {};
            types[plus.networkinfo.CONNECTION_UNKNOW] = "未知";
            types[plus.networkinfo.CONNECTION_NONE] = "未连接网络";
            types[plus.networkinfo.CONNECTION_ETHERNET] = "有线网络";
            types[plus.networkinfo.CONNECTION_WIFI] = "WiFi网络";
            types[plus.networkinfo.CONNECTION_CELL2G] = "2G蜂窝网络";
            types[plus.networkinfo.CONNECTION_CELL3G] = "3G蜂窝网络";
            types[plus.networkinfo.CONNECTION_CELL4G] = "4G蜂窝网络";
            NetStateStr = types[plus.networkinfo.getCurrentType()];

            return NetStateStr;
        };
        /**
         * @description 判断是否有网络
         */
        MobileFrame.IsNetWorkCanUse = function() {
            var IsCanUseNetWork = false;
            if (GetNetWorkState() == \'未知\' || GetNetWorkState() == \'未连接网络\') {
                IsCanUseNetWork = false;
            } else {
                IsCanUseNetWork = true;
            }
            return IsCanUseNetWork;
        };
    })();
    /**
     * @description 定义模块功能-图片工具类
     */
    define(\'scripts/Core/ImageUtil.js\', function(exports) {
        /**
         * @description 图片加载工厂,包含图片加载方法
         * 例如:时间戳控制缓存,下载队列批次下载,默认图片,下载loading图片,下载失败图片
         * 注意相对路径在android:/sdcard/Android/data/io.dcloud.HBuilder/.HBuilder/...
         * ios:/Library/Pandora/...
         */
        (function(ImgLoaderFactory) {
            /**
             * 默认的options
             */
            var defaultSettingOptions = {
                //默认的图片缓存目录-存到应用的downloads/imgs下
                \'imgStoragePath\': "_downloads/imgs/",
                //默认图片的基座路径
                \'defaultImgBase\': \'../../img/mobileFrame/\',
                //loading图片的名称
                \'loadingImgName\': \'img_loading.jpg\',
                //error图片名称
                \'errorImgName\': \'img_error.jpg\',
                //图片缓存的时间戳,毫秒单位,默认为1天
                \'imgsTimeStamp\': 1000 * 60 * 60 * 24 * 1,
                //同时最多的downloader 并发下载数目,默认为3个
                \'concurrentDownloadCount\': 3,
                //单个下载任务最大的请求时间,防止一些机型上无法触发错误回调,单位毫秒,默认10秒
                \'maxTimeSingleDownloadTaskSpend\': 1000 * 10
            };
            //默认的下载图片临时变量
            var defaultLoadingImg = defaultSettingOptions[\'defaultImgBase\'] + defaultSettingOptions[\'loadingImgName\'];
            //默认的显示图片临时变量
            var defaultImg = defaultSettingOptions[\'defaultImgBase\'] + defaultSettingOptions[\'errorImgName\'];
            /**
             * 图片缓存的session头部
             */
            var imageSessionKey_header = \'imageSessionKey_util_imgs_\';
            /**
             * 图片缓存的session的管理者
             */
            var imageSessionManagerKey = \'imageSessionKey_util_Manager\';
            /**
             * 图片缓存池,用来解决多张图片并发请求问题
             * 默认是空的,当有多张图片是同一个请求时,缓存池子中会有数据
             * 格式  {\'url1\':[dom1,dom2]}
             */
            var requestImgsPool = {};
            /**
             * 并发下载任务,包括下载队列,处理最大并发数下载
             */
            var concurrentDownloadTask = {
                //任务池-还没有下载的任务
                Queue: [],
                //当前正在下载的任务数量
                CurrentTaskCount: 0
            };
            /**
             * 当前的任务队列,包含任务的名称,以及时间戳-用来控制最大的超时时间,防止不能正常触发回调
             * 包含:
             * taskObj,timeBegin
             * 格式:{url1:{task1,time1}}
             */
            var currentDownloadTasks = {};
            /**
             * @description 将对应的图片缓存键值添加进入图片缓存管理中
             * @param {String} key 图片路径对应的key
             */
            function addImageSessionKeyToManager(key) {
                //获取管理者
                var manager = plus.storage.getItem(imageSessionManagerKey);
                if (manager == null) {
                    //如果以前的缓存为空,生成缓存
                    manager = [];
                } else {
                    try {
                        manager = JSON.parse(manager);
                    } catch (e) {}
                }
                if (manager.indexOf(key) == -1) {
                    manager.push(key);
                }
                plus.storage.setItem(imageSessionManagerKey, JSON.stringify(manager));
            };
            /**
             * @description 从缓存管理中移除相应的图片缓存
             * @param {String} key 图片路径对应的key
             */
            function removeImageSessionKeyFromManager(key) {
                //获取管理者
                var manager = plus.storage.getItem(imageSessionManagerKey);
                if (manager == null) {
                    //这时候肯定没有离线缓存
                    return;
                }
                try {
                    manager = JSON.parse(manager);
                } catch (e) {}
                var index = -1;
                for (var i = 0; i < manager.length || 0; i++) {
                    if (manager[i] == key) {
                        index = i;
                    }
                }
                if (index != -1) {
                    //删除对应的index位置
                    manager.splice(index, 1);
                    //重新存储
                    plus.storage.setItem(imageSessionManagerKey, JSON.stringify(manager));
                }
            };

            /**
             * 设置图片缓存key
             * @param {String} url
             * @param {JSON} value 存进去的是图片相关的所有属性,包括时间戳,本地路径等
             */
            function setImageSessionItem(url, value) {
                if (url == null) {
                    return;
                }
                //然后添加进入缓存管理者中
                addImageSessionKeyToManager(url);
                url = imageSessionKey_header + MobileFrame.getRelativePathKey(url);
                value = (value != null) ? value : \'\';
                value = (typeof(value) == \'string\') ? value : JSON.stringify(value);
                plus.storage.setItem(url, value);

            };
            /**
             * 获取图片缓存key
             * @param {String} url
             * @return {JSON} item 返回的是一个json对象,包括图片相关的所有属性,包括时间戳,本地路径等
             * @example 包含属性:time localPath
             */
            function getImageSessionItem(url) {
                if (url == null) {
                    return null;
                }
                //去除非法字符
                url = imageSessionKey_header + MobileFrame.getRelativePathKey(url);
                var item = plus.storage.getItem(url);
                try {
                    if (item != null) {
                        item = JSON.parse(item);
                    }
                } catch (e) {}
                return item;
            };
            /**
             * 移除图片缓存key
             * @param {String} url
             */
            function removeImageSessionItem(url) {
                if (url == null) {
                    return null;
                }
                removeImageSessionKeyFromManager(url);
                //去除非法字符
                url = imageSessionKey_header + MobileFrame.getRelativePathKey(url);
                var items = plus.storage.removeItem(url);
            };
            /**
             * @description 设置图片的src地址,根据一个url,为所有需要的图片赋值
             * @param {htmlElement} $img 图片的dom,这里为原生dom对象
             * @param {String} srcUrl 图片的路径
             * @param {String} relativePath 相对路径,用来判断缓存池的
             */
            function setImgSrc($img, srcUrl, relativePath) {
                if (!srcUrl) {
                    return;
                }
                setImgSrcByDom($img, srcUrl);
                //如果缓存池子中存在图片
                if (!relativePath) {
                    return;
                }
                var relativePathKey = MobileFrame.getRelativePathKey(relativePath);
                if (requestImgsPool && requestImgsPool[relativePathKey]) {
                    var imgsData = requestImgsPool[relativePathKey];
                    //如果是数组
                    if (Array.isArray(imgsData)) {
                        for (var i = 0; i < imgsData.length; i++) {
                            setImgSrcByDom(imgsData[i], srcUrl);
                        }
                    } else {
                        //单条数据--单个dom对象
                        setImgSrcByDom(imgsData, srcUrl);
                    }
                    if (srcUrl != defaultLoadingImg) {
                        //如果不是loading图片就清空
                        //清空图片池子中的该条键值
                        requestImgsPool[relativePathKey] = null;
                    }
                }
            };
            /**
             * @description 设置图片的src地址,一个dom和一个 src一一对应
             * @param {HTMLElement} $img 图片的dom,原生dom对象
             * @param {String} srcUrl 图片的路径
             */
            function setImgSrcByDom($img, srcUrl) {
                if (!$img || !($img instanceof HTMLElement)) {
                    //console.log(\'该dom不是原生对象,url:\' + srcUrl);
                    return;
                }
                //暂时去除loading图片的独特样式
//              if (srcUrl == defaultLoadingImg) {
//                  //默认的loading图片,修改css
//                  $img.style.maxWidth = \'30px\';
//                  $img.style.maxHeight = \'30px\';
//              } else {
//                  //恢复普通高度
//                  $img.style.maxWidth = \'100%\';
//                  $img.style.maxHeight = \'100%\';
//              }
                srcUrl = MobileFrame.changImgUrlTypeNoCache(srcUrl);
                $img.setAttribute(\'src\', srcUrl);
            };
            /**
             * @description 移除所有的图片缓存键
             */
            function clearAllImageSessionKey() {
                MobileFrame.plusReady(function() {
                    var manager = plus.storage.getItem(imageSessionManagerKey);
                    if (manager == null) {
                        //这时候肯定没有离线缓存
                        return;
                    }
                    try {
                        manager = JSON.parse(manager);
                    } catch (e) {}
                    if (Array.isArray(manager)) {
                        for (var i = 0; i < manager.length; i++) {
                            removeImageSessionItem(manager[i]);
                        }
                    }
                });

            };
            /**
             * @description 设置图片加载工具的一些基本参数
             * @param {JSON} options 参数
             * @example 参数没传代表使用默认值,包括:
             * imgStoragePath,string型,图片的默认路径
             * defaultImgBase,string型,默认图片的基座路径
             */
            ImgLoaderFactory.setOptions = function(options) {
                if (!options) {
                    return;
                }
                //设置参数
                for (var key in defaultSettingOptions) {
                    //如果设置的是有效的
                    if (options[key] != null) {
                        defaultSettingOptions[key] = options[key];
                    }
                }
                //默认的下载图片临时变量
                defaultLoadingImg = defaultSettingOptions[\'defaultImgBase\'] + defaultSettingOptions[\'loadingImgName\'];
                //默认的显示图片临时变量
                defaultImg = defaultSettingOptions[\'defaultImgBase\'] + defaultSettingOptions[\'errorImgName\'];
            };
            /**
             * @description 清除图片加载工厂的所有图片缓存
             * @param {Function} successCallback 成功回调
             * @param {Function} errorCallback 失败回调
             */
            ImgLoaderFactory.clearLoaderImgsCache = function(successCallback, errorCallback) {
                MobileFrame.plusReady(function() {
                    //遍历目录文件夹下的所有文件,然后删除
                    var tmpUrl = plus.io.convertLocalFileSystemURL(defaultSettingOptions[\'imgStoragePath\']);
                    //需要手动加上 file://
                    tmpUrl = \'file://\' + tmpUrl;
                    //同时清除所有的缓存键值
                    clearAllImageSessionKey();
                    plus.io.resolveLocalFileSystemURL(tmpUrl, function(entry) {
                        entry.removeRecursively(function() {
                            if (successCallback && typeof(successCallback) == \'function\') {
                                successCallback(\'清除图片缓存成功!\');
                            }
                        }, function() {
                            if (errorCallback && typeof(errorCallback) == \'function\') {
                                errorCallback(\'清除图片缓存失败!\');
                            }
                        });
                    }, function(e) {
                        if (errorCallback && typeof(errorCallback) == \'function\') {
                            errorCallback(\'打开图片缓存目录失败!\');
                        }
                    });
                });
            };
            /**
             * @description 从一个网络URL中,获取本地图片缓存相对路径
             * @param {String} loadUrl 图片的网络路径,如果为null,则返回一个null
             * @return {String} 返回路径或者是 ***outOfTime***表示缓存时间戳过去
             * @example 获取相对路径可以有很多种方法
             * 比如可以用md5将url加密,或者其它字符串操作等等
             * 我这里也是根据项目而进行自适应的
             */
            ImgLoaderFactory.getRelativePathFromLoadUrl = function(loadUrl) {
                if (loadUrl == null) return null;
                //如果loadUrl以../开头,代表是相对路径,采用本地相对路径,这里就直接返回本地路径,这样就是直接赋值了
                if (loadUrl.substring(0, 5).indexOf(\'../\') != -1) {
                    return loadUrl;
                }
                //图片缓存如果存在,判断是否过期,默认为\'\'
                var isOutOfTimeHeader = \'\';
                //如果存在本地缓存,并且没有过期,采用本地缓存中的图片
                var loacalImgSessionItem = getImageSessionItem(loadUrl);
                if (loacalImgSessionItem != null) {
                    //判断是否过期  time localPath
                    if (loacalImgSessionItem.time) {
                        loacalImgSessionItem.time = parseInt(loacalImgSessionItem.time, 10);
                        if ((new Date()).valueOf() - loacalImgSessionItem.time > defaultSettingOptions[\'imgsTimeStamp\']) {
                            //console.log(\'当前缓存已经过期\')
                            //返回一个特殊字符,代表过期 
                            isOutOfTimeHeader = \'***outOfTime***\';
                        } else {
                            //console.log(\'缓存未过期\');
                        }
                    }
                    if (loacalImgSessionItem.localPath) {
                        return loacalImgSessionItem.localPath;
                    }
                }
                //获取图片后缀,如果没有获取到后缀,默认是jpg
                var imgSuffix = loadUrl.substring(loadUrl.lastIndexOf(".") + 1, loadUrl.length);
                if (
                    imgSuffix.toLocaleLowerCase() != ("jpg") &&
                    imgSuffix.toLocaleLowerCase() != ("jpeg") &&
                    imgSuffix.toLocaleLowerCase() != ("png") &&
                    imgSuffix.toLocaleLowerCase() != ("bmp") &&
                    imgSuffix.toLocaleLowerCase() != ("svg") &&
                    imgSuffix.toLocaleLowerCase() != ("gif")
                ) {
                    //如果后缀没有包含以上图片,将后缀改为jpg
                    imgSuffix = \'jpg\';
                }
                //更换存储方式,变为将整个路径存储下来,然后去除非法字符
                var regIllegal = /[&\\|\\\\\\*^%$#@\\-:.?\\/=!]/g;
                //获取图片名字
                var imgName = loadUrl.replace(regIllegal, \'\');
                //最终的名字
                var filename = imgName + \'.\' + imgSuffix;
                //console.log(\'loadurl:\'+loadUrl+\',fileName:\'+filename);
                var relativePath = defaultSettingOptions[\'imgStoragePath\'] + filename;
                setImageSessionItem(loadUrl, {
                    \'localPath\': relativePath,
                    \'time\': (new Date()).valueOf()
                });
                //将是否过期标识传出
                return isOutOfTimeHeader + relativePath;
            };

            /**
             * @description 删除某一张网络图片的本地缓存,同时也会删除缓存键值
             */
            ImgLoaderFactory.clearNetUrlImgCache = function(netImgUrl, successCallback, errorCallback) {
                MobileFrame.plusReady(function() {
                    //删除该键值对应的缓存
                    removeImageSessionItem(netImgUrl);
                    MobileFrame.delFile(ImgLoaderFactory.getRelativePathFromLoadUrl(netImgUrl), successCallback, errorCallback);
                });
            };

            /**
             * @description 给指定的图片dom 设置本地图片属性
             * @param {HTMLElement} $img 目标图片dom,这里为原生的dom对象
             * @param {String} relativePath 本地图片路径
             */
            function setImgFromLocalCache($img, relativePath) {
                /*例如:
                 * 本地相对路径("downloads/imgs/logo.jpg")转成SD卡绝对路径
                 * 例如相对路径:downloads/imgs/logo.jpg
                 * ("/storage/emulated/0/Android/data/io.dcloud.HBuilder/.HBuilder/downloads/imgs/logo.jpg");
                 * */
                if (!relativePath) {
                    return;
                }
                MobileFrame.plusReady(function() {
                    var sd_path = plus.io.convertLocalFileSystemURL(relativePath);
                    setImgSrc($img, sd_path, relativePath);
                });
            };
            /**
             * @description 通过本地缓存的方法显示网络图片
             * @param {HTMLElement} $img 原生dom对象
             * @param {String} loadUrl loadurl
             */
            ImgLoaderFactory.setImgWidthLocalCache = function($img, loadUrl) {
                if ($img == null || loadUrl == null) return;
                MobileFrame.plusReady(function() {
                    var relativePath = ImgLoaderFactory.getRelativePathFromLoadUrl(loadUrl);
                    //判断需不需要将路径进行编码,如果是中文路径,需要编码后才能下载
                    var regChinese = /[\\u4E00-\\u9FA5]/g;
                    var tmpLoadUrl = loadUrl.replace(regChinese, \'chineseRemoveAfter\');
                    if (tmpLoadUrl.indexOf(\'chineseRemoveAfter\') != -1) {
                        loadUrl = encodeURI(loadUrl);
                    }
                    //判断是否已经缓存过期
                    var isCacheOutOfTime = false;
                    if (relativePath.indexOf(\'***outOfTime***\') != -1) {
                        relativePath.replace(\'***outOfTime***\', \'\');
                        isCacheOutOfTime = true;
                    }
                    if (relativePath == \'default.jpg\') {
                        //设置默认图片
                        setImgSrc($img, defaultImg);
                    } else {
                        if (isCacheOutOfTime == false) {
                            //检查图片是否已存在
                            plus.io.resolveLocalFileSystemURL(relativePath, function(entry) {
                                //如果文件存在,则直接设置本地图片
                                setImgFromLocalCache($img, relativePath);
                            }, function(e) {
                                readyToGetNetImg($img, loadUrl, relativePath);
                            });
                        } else {
                            //否则,本地缓存已经过期,直接网络获取
                            readyToGetNetImg($img, loadUrl, relativePath);
                        }
                    }
                });
            };
            /**
             * @description 准备通过网络获取图片
             * @param {HTMLElement} $img 原生dom对象
             * @param {String} loadUrl loadurl
             * @param {String} relativePath 本地相对路径
             Swift新async/await并发中利用Task防止指定代码片段执行的数据竞争(Data Race)问题

根据图片的url地址下载图片到本地保存代码片段

vue360图片没法缓存

UWP开发中两种网络图片缓存方法

图片三级缓存的流程

IOS把图片缓存到本地的几种方法