며칠 전, 이전 프로젝트에서 쿠키 작동이 매우 이상하다는 사실을 발견했습니다. 상담 후 URL에 매개변수가 전달되지 않도록 일부 정보를 캐시하고 싶었지만 쿠키가 발생할 수 있는 문제는 고려하지 않았습니다. 원인:
① 쿠키 크기는 약 4k로 제한되어 비즈니스 데이터 저장에 적합하지 않습니다.
② 쿠키는 매번 HTTP 트랜잭션과 함께 전송되므로 대역폭이 낭비됩니다
저희는 모바일 프로젝트를 진행하고 있는데, 여기서 정말 활용하기 적합한 기술은 로컬 스토리지입니다. 로컬 스토리지는 쿠키의 최적화라고 할 수 있습니다. 클라이언트에 데이터를 편리하게 저장하는 데 사용할 수 있으며, HTTP이지만 문제 없습니다.
결함이 장점을 숨기지 않고 위의 문제를 피할 수 있으므로 로컬 스토리지를 어떻게 사용하는지, 어떻게 올바르게 사용하는지에 초점을 맞춰야 합니다.
① sessionStrage: 세션은 세션을 의미합니다. 여기서 세션은 사용자가 웹사이트를 탐색할 때 웹사이트에 입장한 후 웹사이트를 닫을 때까지의 기간을 의미합니다.
② localStorage: 데이터가 무엇이든 클라이언트 하드웨어 장치에 데이터를 저장합니다. 즉, 다음에 컴퓨터를 켤 때 데이터가 그대로 유지됩니다.
둘의 차이점은 하나는 임시 보관용이고 다른 하나는 장기 보관용이라는 점입니다.
기본 사용법을 설명하는 간단한 코드는 다음과 같습니다.
클립보드에 콘텐츠 복사
- <div id="msg" 스타일="여백: 10px 0; 테두리: 1px 단색 검은색; 패딩: 10px; 너비: 300px;
- 높이: 100px;">
-
div>
-
<입력 유형="텍스트" id="text" />
-
<선택 id="type" >
-
<옵션 값="세션" >세션저장옵션>
-
<옵션 값="로컬" >로컬스토리지옵션>
-
선택>
-
<버튼 클릭="저장( );">
-
保存数据버튼>
-
<버튼 클릭="load( );">
-
读取数据버튼>
-
<스크립트 유형="text/ javascript">
-
var msg = document.getElementById('msg'),
-
텍스트 = 문서.getElementById('text'),
-
유형 = 문서.getElementById('type');
-
-
함수 save() {
-
var str = text.value;
-
var t = type.value;
-
if (t == '세션') {
-
sessionStorage.setItem('msg', str);
-
} 그밖에 {
-
localStorage.setItem('msg', str);
-
}
-
}
-
-
함수 load() {
-
var t = type.value;
-
if (t == '세션') {
-
msg.innerHTML = sessionStorage.getItem('msg');
-
} 그밖에 {
-
msg.innerHTML = localStorage.getItem('msg');
-
}
-
}
-
스크립트>
真实场景
实际工作中对localstorage를 사용하는 데 사용하는 일이 없습니다.
① 缓存一般信息,如搜索页적 OUT发citycity,达到citycity ,不实时定位信息
② 缓存citycity列表数据,这个数据往往比较大
③ 每条缓存信息需要可追踪,比如服务器communicationcitycity数据更new,这个时候在最近一次访问的时候要自动设置过期
4 每条信息具有过期日期状态, 在过期外时间需要由服务器拉取数据
XML/HTML 코드复复内容到剪贴板
-
define([], function () {
-
-
var 저장소 = _.inherit({
-
//기본 속성
-
속성: 함수() {
-
-
//프록시 객체, 기본값은 localstorage
-
this.sProxy = 창.localStorage
-
-
//60 * 60 * 24 * 30 * 1000 ms ==30일
-
this.defaultLifeTime = 2592000000
-
-
//로컬 캐시는 모든 localstorage 키 값과 만료 날짜 간의 매핑을 저장하는 데 사용됩니다.
-
this.keyCache = 'SYSTEM_KEY_TIMEOUT_MAP';
-
//캐시 용량이 가득 차면 매번 삭제되는 캐시 개수 -
-
this.removeNum = 5;
-
},
-
-
주장: 함수 () {
- if (
this.sProxy-
=== null) {
throw 'sProxy 속성을 재정의하지 않음'
-
}
-
},
-
-
초기화: 함수(선택) {
-
this.propertys()
-
this.assert()
-
},
-
-
/*
-
로컬 저장소 추가
-
데이터 형식에는 고유 키 값, json 문자열, 만료 날짜, 입금 날짜가 포함됩니다.
-
기호는 동일한 요청에 다른 매개변수가 있을 때 새 데이터를 반환하는 데 사용되는 형식화된 요청 매개변수입니다. 예를 들어 목록이 베이징 시이고 상하이로 전환된 경우 태그가 다음과 같은 것으로 판단됩니다. 다르며 캐시된 데이터를 업데이트합니다. 태그는 서명
과 동일합니다.
-
각 키 값에 대해 하나의 정보만 캐시됩니다.
-
*/
-
집합: 함수(키, 값, 시간 초과, 부호) {
-
var _d = 새 날짜()
-
//입금일
-
var indate = _d.getTime()
-
-
//최종 저장 데이터
-
var 엔티티 = null;
-
if (!timeout) { -
_d.setTime(_d.getTime() this.defaultLifeTime) -
-
시간 초과 = _d.getTime()
} -
-
// -
this.setKeyCache(key, timeout) -
-
entity = this.buildStorageObj(value, indate, timeout, sign)
-
시도해보세요 { -
this.sProxy.setItem(key, JSON.stringify(entity)) -
true를 반환합니다. -
} 잡기 (e) { -
//로컬 스토리지가 가득 차면 모두 삭제 -
if (-
e.name == 'QuotaExceededError') {
// this.sProxy.clear() -
-
if (!this.removeLastCache()) throw '이번에 저장된 데이터의 양이 너무 큽니다.'
-
this.set(key, value, timeout, sign)
-
콘솔 && console.log(e) -
}
-
false 반환
-
},
-
-
//만료된 캐시 삭제
-
RemoveOverdueCache: 함수 () {
-
var tmpObj = null, i, len;
-
var -
지금 = new Date().getTime()
//키-값 쌍 가져오기 -
var -
cacheStr = this.sProxy.getItem(this.keyCache)
var -
cacheMap = []
var -
newMap = []
if (!cacheStr) { -
복귀 -
} -
-
-
cacheMap = JSON.parse(cacheStr)
-
for (-
i = 0, len = cacheMap.length; i < len; >
- tmpObj = cacheMap[i]
if (tmpObj.timeout
- < 지금) {
this.sProxy.removeItem(tmpObj.key)
-
} else {
-
newMap.push(tmpObj)
-
- }
- this.sProxy.setItem(this.keyCache, JSON.stringify(newMap))
-
- },
-
-
제거LastCache: 함수() {
-
var i, len
-
var num = this.removeNum || 5;
-
//키-값 쌍 가져오기 -
var -
cacheStr = this.sProxy.getItem(this.keyCache)
var -
cacheMap = []
var -
delMap = []
-
//저장용량이 너무 크다는 표시 -
if (!cacheStr) 반환 false -
-
캐시맵.정렬(함수 (a, b) { -
a.timeout 반환 - b.timeout -
}) -
-
//삭제된 데이터 -
-
delMap = cacheMap.splice(0, num);
for (
i-
= 0, len = delMap.length; i < len; >
this.sProxy.removeItem(delMap[i].key)
- }
-
- this.sProxy.setItem(this.keyCache, JSON.stringify(cacheMap))
- true를 반환합니다.
- },
-
- setKeyCache: 함수(키, 시간 초과) {
- if (!key || !timeout || timeout <
- new Date().getTime( )) 반환
var i, len, tmpObj
-
- //현재 캐시된 키 값 문자열 가져오기
- var oldstr
- = this.sProxy.getItem(this.keyCache)
var oldMap
- = []
//현재 키가 이미 존재하는지 여부
- var 플래그
- = false;
var obj = {};
-
obj.key = key;
-
obj.timeout = 시간 초과;
-
-
if (oldstr) {
-
oldMap = JSON.parse(oldstr);
-
if (!_.isArray(oldMap)) oldMap = [];
-
}
-
-
for (i = 0, len = oldMap.length; i < len; i ) {
-
tmpObj = oldMap[i];
-
if (tmpObj.key == key) {
-
oldMap[i] = obj;
-
플래그 = 참;
-
휴식;
-
}
-
}
-
if (!flag) oldMap.push(obj);
-
//最后将新数组放到缓存中
-
this.sProxy.setItem(this.keyCache, JSON.stringify(oldMap));
-
-
},
-
-
buildStorageObj: 함수 (값, indate, timeout, sign) {
-
var obj = {
-
값: 값,
-
시간 초과: 시간 초과,
-
기호: 서명,
-
indate: indate
-
};
-
obj 반환;
-
},
-
-
get: 함수(키, 기호) {
-
var 결과, now = new Date().getTime()
-
시도해보세요 {
-
결과 = 이.sProxy.getItem(key)
-
if(!result)는 null을 반환합니다.
-
결과 = JSON.parse(결과)
-
-
//데이터 만료
-
if (result.timeout < now) return null;
-
//서명확인이 필요합니다 -
if (부호) { -
if (-
sign === result.sign)
결과.값 반환 -
null 반환 -
} else { -
결과.값 반환 -
-
-
} 잡기 (e) {
-
콘솔 && console.log(e)
-
}
-
null 반환
-
},
-
-
//서명 받기
-
getSign: 함수(키) {
- var 결과,
sign-
= null;
시도해보세요 {
- 결과
= -
이.sProxy.getItem(key)
if (결과) {
- 결과
= -
JSON.parse(결과)
sign
= -
결과 && result.sign
} 잡기 (e) {
-
콘솔 && console.log(e)
-
}
-
반환 기호;
-
},
-
-
제거: 기능(키) {
-
return this.sProxy.removeItem(key);
-
},
-
-
지우기: 함수 () {
-
this.sProxy.clear();
-
}
-
});
-
-
Storage.getInstance = 함수 () {
-
if (this.instance) {
-
return this.instance;
-
} 그밖에 {
-
return this.instance = new this();
-
}
-
};
-
-
반납 저장소;
-
-
});
这段代码包含了localstorage的基本操作,并且对以上问题做了处理,而真实的使用还要再抽象:
XML/HTML 코드复复内容到剪贴板
-
define(['AbstractStorage'], function(AbstractStorage) {
-
-
var Store = _.inherit({
-
//기본 속성
-
속성: 함수() {
-
-
//각 객체에는 저장 키가 있어야 하며 반복할 수 없습니다.
-
this.key = null;
-
//데이터의 기본 수명 주기, S는 초, M은 분, D는 일 -
-
this.lifeTime = '30M';
-
//기본 반환 데이터
- //
this.defaultData-
= null
-
//프록시 객체, 로컬 저장소 객체
-
this.sProxy-
= new AbstractStorage()
-
},
-
-
setOption: 함수(옵션) {
-
_.extend(this, 옵션)
-
},
-
-
주장: 함수 () {
- if (
this.key-
=== null) {
'키 속성을 재정의하지 않음'을 발생시킵니다.
-
}
- if (
this.sProxy-
=== null) {
throw 'sProxy 속성을 재정의하지 않음'
-
}
-
},
-
-
초기화: 함수(선택) {
-
this.propertys()
-
this.setOption(opts)
-
this.assert()
-
},
-
-
_getLifeTime: 함수 () {
-
var 시간 초과 = 0;
-
var str = this.lifeTime;
-
var 단위 = str.charAt(str.length - 1);
-
var num = str.substring(0, str.length - 1);
-
var 지도 = {
-
D: 86400,
-
H: 3600,
-
남: 60,
-
대: 1
-
};
-
if (typeof unit == 'string') {
-
단위단위 = unit.toUpperCase();
-
}
-
시간 초과 = 번호;
-
if (단위) 시간 초과 = 지도[단위];
-
-
//单位为毫秒
-
반환 숫자 * 시간 초과 * 1000 ;
-
},
-
-
//缓存数据
-
설정: 함수(값, 기호) {
-
//获取过期时间
-
var timeout = new Date();
-
timeout.setTime(timeout.getTime() this._getLifeTime());
-
this.sProxy.set(this.key, value, timeout.getTime(), sign);
-
},
-
-
//设置单个属性
-
setAttr: 함수(이름, 값, 기호) {
-
var key, obj;
-
if (_.isObject(이름)) {
-
(키 입력 이름) {
-
if (name.hasOwnProperty(key)) this.setAttr(k, name[k], value);
-
}
-
반품;
-
}
-
-
if (!sign) sign = this.getSign();
-
-
//获取当前对象
-
obj = 이것.get(sign) || {};
-
(!obj) return인 경우;
-
obj[이름] = 값;
-
this.set(obj, sign);
-
-
},
-
-
getSign: 함수 () {
-
return this.sProxy.getSign(this.key);
-
},
-
-
제거: 함수 () {
-
this.sProxy.remove(this.key);
-
},
-
-
removeAttr: 함수 (attrName) {
-
var obj = this.get() || {};
-
if (obj[attrName]) {
-
obj[attrName] 삭제;
-
}
-
this.set(obj);
-
},
-
-
get: 함수(부호) {
-
var 결과 = [], isEmpty = true, a;
-
var obj = this.sProxy.get(this.key, sign);
-
var 유형 = 유형 obj;
-
var o = { 'string': true, 'number': true, 'boolean': true };
-
if (o[type]) return obj;
-
-
if (_.isArray(obj)) {
-
for (var i = 0, len = obj.length; i < len; i ) {
-
결과[i] = obj[i];
-
}
-
} else if (_.isObject(obj)) {
-
결과 = obj;
-
}
-
-
(결과적으로) {
-
isEmpty = false;
-
휴식;
-
}
-
return !isEmpty ? 결과 : null;
-
},
-
-
getAttr: 함수(attrName, 태그) {
-
var obj = this.get(tag);
-
var attrVal = null;
-
if (obj) {
-
attrVal = obj[attrName];
-
}
-
attrVal 반환;
-
}
-
-
});
-
-
Store.getInstance = 함수 () {
-
if (this.instance) {
-
return this.instance;
-
} 그밖에 {
-
return this.instance = new this();
-
}
-
};
-
-
매장 반품;
-
});
我们真实使用时候是使用store这个类操事localstorage,代码结束简单测试:
存储完成,以后도불会走请求,于是今天的代码基本结束,最后在android Hybrid中有一后退按钮,此按钮一旦按下会回到上一个页면, 这个时候里면적localstorage可能会读取失效!一个简单不靠谱的解决方案是在webapp中加入:
XML/HTML 코드复复内容到剪贴板
-
window.onunload = 함수 () { };//适合单页应用 ,不要问我为什么,我也不知道
结语
localstorage是移动开发必不可少的技术点,需要深入了解,具体业务代码后续会放到git上,有兴趣的朋友可以去了解