-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
第 104 题:模拟 localStorage 时如何实现过期时间功能 #171
Comments
// 模拟实现一个 localStorage |
|
定时器没有清除呢 |
用 cookie 模拟 localStorage
if (!window.localStorage) {
window.localStorage = {
getItem: function (sKey) {
if (!sKey || !this.hasOwnProperty(sKey)) { return null; }
return unescape(document.cookie.replace(new RegExp("(?:^|.*;\\s*)" + escape(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*((?:[^;](?!;))*[^;]?).*"), "$1"));
},
key: function (nKeyId) {
return unescape(document.cookie.replace(/\s*\=(?:.(?!;))*$/, "").split(/\s*\=(?:[^;](?!;))*[^;]?;\s*/)[nKeyId]);
},
setItem: function (sKey, sValue) {
if(!sKey) { return; }
document.cookie = escape(sKey) + "=" + escape(sValue) + "; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/";
this.length = document.cookie.match(/\=/g).length;
},
length: 0,
removeItem: function (sKey) {
if (!sKey || !this.hasOwnProperty(sKey)) { return; }
document.cookie = escape(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
this.length--;
},
hasOwnProperty: function (sKey) {
return (new RegExp("(?:^|;\\s*)" + escape(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie);
}
};
window.localStorage.length = (document.cookie.match(/\=/g) || window.localStorage).length;
} 扩展 localStorage 支持 expires(function () {
var getItem = localStorage.getItem.bind(localStorage)
var setItem = localStorage.setItem.bind(localStorage)
var removeItem = localStorage.removeItem.bind(localStorage)
localStorage.getItem = function (keyName) {
var expires = getItem(keyName + '_expires')
if (expires && new Date() > new Date(Number(expires))) {
removeItem(keyName)
removeItem(keyName + '_expires')
}
return getItem(keyName)
}
localStorage.setItem = function (keyName, keyValue, expires) {
if (typeof expires !== 'undefined') {
var expiresDate = new Date(expires).valueOf()
setItem(keyName + '_expires', expiresDate)
}
return setItem(keyName, keyValue)
}
})() 使用localStorage.setItem('key', 'value', new Date() + 10000) // 10 秒钟后过期
localStorage.getItem('key') |
搞不懂啊 |
localstorage本身没有时间过期的功能,要是自己封装一个简单的localstorage功能的话,可以使用定时器去实现过期时间的功能,值得注意的是执行定时器后,到指定的时间,记得destroy定时器。
测试代码(vue代码)
|
感觉不能用定时器,因为浏览器会关闭。不知道我感觉的对不对 |
??存储的时候加个存储时间戳和有效期时长就好了啊。取的时候判断一下不就行了 |
浏览器切换下一个页签定时器有可能被暂停 |
使用定时器来做过期时间功能的话,重复设置某个值,如果第二次有效期比第一次长,那么到期之前,第一次已经将它清空了。
|
定时器问题,每次set除了要创建新定时器,还要清空已存在的定时器,亦即每次set都会更新定时器,就不必担心旧的定时器清空新set的值了。上面的处理貌似都没在set的时候处理定时器。 更重要的, localStorage要刷新后依然存在。貌似只有cookie模拟的实现了这个特性。
总之使用关键字的形式,可能会因为特殊key的设置导致其他某些key的过期功能失效或不按预期执行。 所以个人还是更支持用定时器的方式。 可能看起来有点吹毛求疵。 只是实际面试中,面试官看到你的答案后,可能会加问一句,“这个方案可能会有什么潜在问题。 ” |
参照楼下的做下总结,实现过期时间 两种常见的方案: |
setTimeout不能保证到时间点就执行吧 |
const localStorage = (function () {
let store = {}
return {
getItem: function (key) {
return store[key] || null
},
setItem: function (key, val, time) {
time = Number(time) || 0;
store[key] = val.toString();
if (time > 0) {
this.timeOut(key, time);
}
},
timeOut: function (key, time) {
var timer = setTimeout(() => {
this.removeItem(key);
clearTimeout(timer)
}, time);
},
removeItem: function (key) {
delete store[key]
},
clear: function () {
store = {}
}
}
})()
Object.defineProperty(window, 'localStorage2', {
value: localStorage
}) |
|
localStorage最主要的能力是本地存储,即使关闭浏览器还是存在的,因此基于cookie做个模拟 function setCookie(key, value = '', days) {
if (!key) return
let date = new Date()
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000); // 设置过期时间为 days 天之后
document.cookie = key + "=" + decodeURIComponent(value) + ";expires=" + date.toGMTString();
}
function getCookie(key) {
let result = ''
let cookie = document.cookie + ";"
let queryString = key + "="
let start = cookie.indexOf(queryString)
if (start > -1) {
start += queryString.length
let end = cookie.indexOf(";", start)
result = (cookie.substring(start, end))
}
// return getCookies()[key]
return result
}
function getCookies() {
let result = {}
if (!document.cookie) return result
document.cookie.split(';').forEach((item) => {
const [key, value] = item.split('=')
result[key.trim()] = value.trim()
})
return result
}
window.localStorage = window.localStorage || new LocalStorage()
function LocalStorage() {
const cookies = getCookies()
this.length = Object.keys(cookies).length
for (let [key, value] of Object.entries(cookies)) {
this[key] = value
}
}
LocalStorage.prototype = function () {
function getItem(key) {
return getCookie(key);
}
function setItem(key, value, days) {
this[key] = value
this.length++
setCookie(key, value, days)
}
function removeItem(key) {
this.length--
delete this[key]
setItem(key, '', -1);
}
function clear() {
const cookies = getCookies();
for (let key of Object.keys(cookies)) {
delete this[key]
removeItem(key);
}
this.length = 0
}
return {
constructor: LocalStorage,
getItem,
setItem,
removeItem,
clear,
}
}() |
其实只需要在获取数据的时候判断数据的时间是否已经过期就好了,最多再加一个time interval 去定时遍历数据的过期时间。 |
在set key的时候 加上一个timestamp |
随便写了一个,麻烦大家看一下有没有不对。setItem的时候同时保存过期时间戳,同时可以根据需要是否自行定时检查。主要写一下思路,没有做过多的值的合法检查,关于值的合法检查的问题就不要批评我了。 class ExpirableLocalStorage {
/**
* 设置localStorage键值对
* @param {Integer} expires 过期时间戳
*/
static setItem(key, value, expires) {
if (expires < Date.now()) {
this.removeItem(key);
return;
}
window.localStorage.setItem(key, value);
window.localStorage.setItem(`expires_${key}`, expires);
}
/**
* 获取localStorage值
*/
static getItem(key) {
if (parseInt(window.localStorage.getItem(`expires_${key}`)) < Date.now()) {
this.removeItem(key);
return null;
}
return window.localStorage.getItem(key);
}
/**
* 移除localStorage键值对
*/
static removeItem(key) {
window.localStorage.removeItem(key);
window.localStorage.removeItem(`expires_${key}`);
}
/**
* 检查过期的键值对并移除
*/
static checkExpired() {
for (let i = 0, len = window.localStorage.length; i < len; i++) {
const key = window.localStorage.key(i);
const value = window.localStorage.getItem(key);
const expires = window.localStorage.getItem(`expires_${key}`);
if (value && expires && expires < Date.now()) {
this.removeItem(key);
}
}
}
/**
* 定时检查
*/
static timingCheck(interval = 1000) {
if (ExpirableLocalStorage.timer) {
clearInterval(ExpirableLocalStorage.timer);
}
ExpirableLocalStorage.timer = setInter(() => {
this.checkExpired();
}, interval);
}
} |
使用方法好像expire参数需要修改一下: |
模拟cookie功能,之前写了个lib: https://github.com/pagemarks/codes/blob/master/js/cache.js function getStorage(isSession) {
return isSession ? sessionStorage : localStorage;
}
const cache = {
get(key, isSession = true, val = null) {
const storage = getStorage(isSession);
let ret = storage.getItem(key);
if (!ret && val !== null) return val; //default val
const char = ret && ret.slice(0, 1);
if (char && (char === '{' || char === '[')) {
ret = JSON.parse(ret);
if (ret.expires) {
if (ret.expires >= Date.now()) {
if ('value' in ret && Object.keys(ret).length === 2) {
ret = ret.value;
} else {
delete ret.expires;
}
} else {
ret = val !== null ? val : null;
this.del(key, isSession)
}
}
} else if (ret === 'true' || ret=== 'false') {
ret = ret === 'true';
}
return ret;
},
hget(key, hash, isSession = true) {
return this.get(key, isSession, {})[hash];
},
set(key, value, isSession = true, seconds = 0) {
const storage = getStorage(isSession);
let val = value;
if (seconds) {
const expires = Date.now() + seconds;
val = Object.assign({}, typeof value === 'object' ? value : { value }, { expires });
}
if (typeof value === 'object') val = JSON.stringify(val);
storage.setItem(key, val);
},
hset(key, hash, val, isSession = true) {
const ob = this.get(key, isSession, {});
ob[hash] = val;
this.set(key, ob, isSession);
},
del(key, isSession = true) {
const storage = getStorage(isSession);
storage.removeItem(key);
}
};
export default cache; |
cookie 只能存那么一点东西, 你有cookie模拟意义在哪里 |
// Custom storage object
const storage: StateStorage = {
getItem(key) {
const itemStr = localStorage.getItem(key)
// if the item doesn't exist, return null
if (!itemStr) {
return null
}
const item = JSON.parse(itemStr)
const now = new Date()
// compare the expiry time of the item with the current time
if (now.getTime() > item.expiry) {
// If the item is expired, delete the item from storage
// and return null
localStorage.removeItem(key)
return null
}
return item.value
},
setItem(key, value) {
const now = new Date()
// `item` is an object which contains the original value
// as well as the time when it's supposed to expire
const item = {
value: value,
expiry: now.getTime() + 7 * 24 * 60 * 60 * 1000, // 7 days
}
localStorage.setItem(key, JSON.stringify(item))
},
// remove the entry with the given key
removeItem(key) {
window.localStorage.removeItem(key)
},
} |
No description provided.
The text was updated successfully, but these errors were encountered: