local_cache 本地缓存 资源版本管理 js资源缓存
OTT端性能优化建设之本地缓存设计 | 《优酷OTT互联网大屏前端技术实践》第七章-阿里云开发者社区 - Google Chrome
local_cache.js
// local_cache.js // 原文地址:https://developer.aliyun.com/article/771774 // 源码地址:https://g.alicdn.com/de/local_cache/0.0.1/page/localStorage/index.js // 实现原理图: https://ucc.alicdn.com/pic/developer-ecology/236bb9fc0b2c4a28bc1710d093117666.png var local_cache = (function () { const oHead = document.getElementsByTagName('head')[0] const _localStorage = window.localStorage || {} const nowDateNum = +formatDateTime(false, 'YYYYMMDD') // 创建ajax函数 let ajax = function (_options) { const options = _options || {} options.type = (options.type || 'GET').toUpperCase() options.dataType = options.dataType || 'javascript' const params = options.data ? formatParams(options.data) : '' // 创建-第一步 let xhr if (window.XMLHttpRequest) { xhr = new XMLHttpRequest() } else { xhr = ActiveXObject('Microsoft.XMLHTTP') } // 在响应成功前设置一个定时器(响应超时提示) const timer = setTimeout(function () { // 让后续的函数停止执行 xhr.onreadystatechange = null console.log('timeout:' + options.url) options.error && options.error(status) }, options.timeout || 8000) // 接收-第三步 xhr.onreadystatechange = function () { if (xhr.readyState == 4) { clearTimeout(timer) const status = xhr.status if (status >= 200 && status < 300) { options.success && options.success(xhr.responseText, xhr.responseXML) } else { options.error && options.error(status) } } } // 连接和发送-第二步 if (options.type == 'GET') { xhr.open('GET', options.url + '?' + params, true) xhr.send(null) } if (options.type == 'POST') { xhr.open('POST', options.url, true) // 设置表单提交时的内容类型 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') xhr.send(params) } } // 格式化参数 function formatParams(data) { let arr = [] for (let name in data) { arr.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name])) } arr.push(('v=' + Math.random()).replace('.', '')) return arr.join('&') } // 时间戳转日期格式 function formatDateTime(time, format) { const t = (time && new Date(time)) || new Date() let tf = function (i) { return (i < 10 ? '0' : '') + i } return format.replace(/YYYY|MM|DD|hh|mm|ss/g, function (a) { switch (a) { case 'YYYY': return tf(t.getFullYear()) break case 'MM': return tf(t.getMonth() + 1) break case 'DD': return tf(t.getDate()) break case 'hh': return tf(t.getHours()) break case 'mm': return tf(t.getMinutes()) break case 'ss': return tf(t.getSeconds()) break } }) } function handleError(url, callback, _send) { let script = document.createElement('script') script.type = 'text/javascript' script.onload = script.onreadystatechange = function () { if (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') { console.log('create script loaded : ' + url) callback && callback() _send && _send() script.onload = script.onreadystatechange = null } } script.onerror = function () { console.log('create script error : ' + url) _send && _send() script.onload = null } script.src = url oHead.appendChild(script) } // eval js字符串代码 function _eval(fnString) { window['eval'].call(window, fnString) } function autoDel() { if (!_localStorage.setItem) { return } for (let key in _localStorage) { const value = key.indexOf('##') > -1 ? _localStorage.getItem(key) : '' const isSetExpire = value.split('##').length > 1 const date = isSetExpire && value.split('##')[1] const isExpire = date && nowDateNum > +date.replace(/-/gi, '') if (isExpire) { _localStorage.removeItem(key) _localStorage.removeItem(key + '_data') console.log('DEL:' + key + '|' + key + '_data') } } } function del(lists = []) { if (!Array.isArray(lists)) return for (let key in lists) { _localStorage.removeItem(key) _localStorage.removeItem(key + '_data') console.log('DEL:' + key + '|' + key + '_data') } } let onIndex = -1 let send = function (list = [], index = 0) { if (!Array.isArray(list)) return const num = list.length if (!num || num < index + 1) { autoDel() return } if (index <= onIndex) { return } onIndex = index const item_url = list[index].url const item_aliases = list[index].aliases const callback = list[index].callback const isStorage = list[index].storage !== false if (!_localStorage) { handleError(item_url, callback) send(list, index + 1) return } const isDone = item_url === (_localStorage.getItem && _localStorage.getItem(item_aliases)) if (isDone) { const fnString = _localStorage.getItem(item_aliases + '_data') try { _eval(fnString) } catch (e) { console.log('eval error') } callback && callback() console.log('local:' + item_aliases) send(list, index + 1) return } ajax({ url: item_url, success: function (response, xml) { // 请求成功后执行 try { _eval(response) } catch (e) { console.log('eval error') } callback && callback() console.log('ajax:' + item_aliases) const isSetExpire = item_url.split('##').length > 1 const date = isSetExpire && item_url.split('##')[1] const isExpire = date && nowDateNum > +date.replace(/-/gi, '') if (isStorage && _localStorage.setItem && !isExpire) { try { _localStorage.setItem(item_aliases, item_url) _localStorage.setItem(item_aliases + '_data', response) } catch (oException) { if (oException.name == 'QuotaExceededError') { console.log('超出本地存储限额!') _localStorage.clear() _localStorage.setItem(item_aliases, item_url) _localStorage.setItem(item_aliases + '_data', response) } } } send(list, index + 1) }, error: function (status) { // 失败后执行 console.log('ajax ' + item_aliases + ' error') handleError(item_url.replace('2580', ''), callback, function () { send(list, index + 1) }) setTimeout(function () { send(list, index + 1) }, 300) }, }) } return { send, del } })()
使用方法
local_cache.send([ { aliases: 'jquery', url: 'https://cdn.bootcss.com/jquery/1.9.1/jquery.min.js', }, { aliases: 'vue', url: 'https://cdn.staticfile.org/vue/2.6.9/vue.js', callback: () => { console.log('vue loaded') } } ])
更新版本
local_cache.send([ { aliases: 'jquery', url: 'https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js', }, { aliases: 'vue', url: 'https://cdn.staticfile.org/vue/2.6.9/vue.js', callback: () => { console.log('vue loaded') // 启动项目 init() } } ])
更新版本2
其实也可以通过强行注入 ?v=1.7 这种方式来更新。
local_cache.send([ { aliases: 'jquery', url: 'https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js?v=1.1', }, ])
删除依赖
local_cache.del(['jquery-1.9.1'])
设置过期时间
如果超出过期时间,缓存将被自动删除,并且总是拉取最新的资源。但不再进行缓存了。(暂时不知道使用场景)
local_cache.send([ { aliases: 'jquery', url: 'https://cdn.bootcss.com/jquery/1.9.1/jquery.min.js##2018-08-10', }, ])
禁止缓存
只拉取资源,但不进行缓存。(暂时不知道使用场景,为啥不使用 script:src 直接引入呢?)
local_cache.send([ { aliases: 'jquery', url: 'https://cdn.bootcss.com/jquery/1.9.1/jquery.min.js##2018-08-10', storage: false }, ])
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
2018-03-04 sass 的学习