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();