web storage 안전하게 사용하기
본인이 프로그래머스 데브코스를 수강할 때 바닐라 자바스크립트 멘토님께서 localStorage를 다음과 같이 사용하셨다.
const storage = window.localStorage; const getItem = (key, fallbackValue) => { try { const res = storage.getItem(key); return res ? JSON.parse(res) : fallbackValue; } catch (e) { console.error(e.message); return fallbackValue; } }; export default { getItem, setItem, };
당시에 위 코드의 getItem 내부에서 왜 try ~ catch 문을 써야하는지가 이해가 안됐다. 그때는 워낙 수업 따라가기가 벅차 제대로 짚고 넘어가지 못한 부분이었는데 개발을 하면서 다시 마주치게되어 정리하게 됐다. 이유는 다음 두 가지다.
- JSON.parse시 발생할 수 있는 에러
- localStorage가 지원되지 않는 환경에서 발생하는 에러
1은 다음과 같다. storage에 저장할 때는 JSON.stringify를 이용해서 저장하는데 어떤 경유로 { a : 1
이라는 객체가 저장됐다고 가정해보자. 그리고 이 객체를 다시 가져와서 JSON.parse 하려고 할때 다음과 같은 에러가 발생하게 된다.
에러가 의미하는대로, 두번째 프로퍼티(at position2)가 와야하는데 생략이 되었거나, 두번째 프로퍼티가 오지는 않는데 }
를 기입하지 않아서 발생하는 에러다. 만약 아래와 같이 try ~ catch를 사용하지 않고 코드를 작성하면 프로그램이 멈출수도 있기 때문에 catch 문에서 에러를 포착하여 fallbackValue를 내놓는 것이다.
const res = JSON.parse(localStorage.getItem(2)); // 에러 발생 console.log(res); // 실행되지 않음
2는 다음과 같다. 우선 Can i use?를 통해 localStorage와 sessionStorage가 어떤 브라우저에서 지원되지 않는지 찾아봤다.
localStorage는 다음과 같다.
sessionStorage는 다음과 같다.
그렇다면 지원이 안되 는 상황에서 코드가 작동하도록 하기 위해서는 어떻게 작성해야 할까? How to Use LocalStorage Safely에서는 다음과 같이 사용하는 것을 제시하고 있다.
function isSupportLS() { try { localStorage.setItem('_ranger-test-key', 'hi'); localStorage.getItem('_ranger-test-key'); localStorage.removeItem('_ranger-test-key'); return true; } catch (e) { return false; } } class Memory { constructor() { this.cache = {}; } setItem(cacheKey, data) { this.cache[cacheKey] = data; } getItem(cacheKey) { return this.cache[cacheKey]; } removeItem(cacheKey) { this.cache[cacheKey] = undefined; } } export const storage = isSupportLS() ? window.localStorage : new Memory();
그러니까 isSupportLS 함수를 실행하여 에러가 발생하면 브라우저 저장소가 아닌 웹사이트 내부의 Memory에 저장하는 방법을 제시하고 있다. 하지만 Javascript Try Catch for Localstorage Detection에서 isSupportLS 보다 더 간단하게, 그리고 Edge case까지 고려하여 작성하는 방법을 제시하고 있다.
function supports_html5_storage() { try { return 'localStorage' in window && window['localStorage'] !== null; } catch (e) { return false; } }
해당 게시글을 들어가면 알겠지만, 위 함수에서 try ~ catch 문을 사용하는 이유는 오래된 Firefox는 쿠키 사용을 꺼놨을 때 예외가 발생할 수 있는 버그가 있다고 한다.
그러므로 코드를 다음과 같이 완성할 수 있게된다.
function supports_html5_storage() { try { return 'localStorage' in window && window['localStorage'] !== null; } catch (e) { return false; } } class Memory { constructor() { this.cache = {}; } setItem(cacheKey, data) { this.cache[cacheKey] = data; } getItem(cacheKey) { return this.cache[cacheKey]; } removeItem(cacheKey) { this.cache[cacheKey] = undefined; } } export const storage = supports_html5_storage() ? window.localStorage : new Memory();