해당 글은 Stop Using localStorage! 를 번역(의역)한 내용입니다. 잘못 번역된 내용이 많을 수 있으니 원본 글을 확인하시는 걸 추천드립니다.
localStorage는 현대 애플리케이션을 위해 설계되지 않았으며 구조화된 복제 알고리즘을 지원하지 않습니다. 제목은 클릭베이트가 아니며 메시지는 단호합니다. ‘localStorage 사용을 그만두세요!’ 여기에는 모호성이 없으며, 우리는 이 충격을 완화시키기 위해 손을 잡고 쿰바야를 부르지 않고 있습니다.
localStorage에 문제가 있나요?
localStorage는 약 2009년에 5MB 문자열 기반 저장소로 등장했습니다. 최근 우리의 주의력이 불안정한 상태이니 몇 가지 핵심 내용으로 바로 들어가 봅시다:
- 문자열 객체: 문자열만 저장할 수 있습니다. 다른 형식의 데이터를 저장하려면 해당 데이터를 문자열로 직렬화하고, 검색하려면 역직렬화해야 합니다. 이 작은 특징은 여러 사이트의 오류를 일으키는 원인 중 하나입니다. 예를 들어, true 또는 false 를 저장할 때, LS 설정에 따라, null, undefined 또는 빈 문자열(‘’)과 관련된 잠재적인 문제가 있을 수 있습니다.
- 역사적으로 느림: localStorage는 데이터를 저장하고 검색하는 데 다소 느립니다. 이는 빈번한 트랜잭션을 필요로 하는 애플리케이션에는 적합하지 않게 만듭니다. 최신 MacBook은 잊으세요, 저전력 장치에서의 벤치마크는 비용을 현실적으로 더 명확하게 보여줄 수 있습니다.
- 크기 제한: localStorage는 5MB의 용량 한도가 있으며, 이는 삭제 대상이 될 수 있습니다. 현대 애플리케이션에는 매우 적은 양입니다. 이렇게 작은 양으로 인코딩된 미디어를 저장하는 것은 어렵습니다. 또한, 이는 고정된 것이 아니며, 웹의 모든 영구 저장소와 마찬가지로 언젠가 브라우저에 의해 삭제될 수 있습니다. 이 부분의 데이터 수명주기를 관리해야 할 것으로 예상되지만, 그에 대한 알림이 없습니다.
- Web Worker 접근 불가: localStorage가 미래를 위한 API이거나 저전력 장치에서 활용되는 동시성을 지원하는 것이 아니라는 것을 이해하셨으면 좋겠습니다.
- 원자성 또는 격리 부재: localStorage는 여러 작업 간에 원자성을 보장하지 않습니다. 쓰여진 내용이 무엇인지 보장하거나 정보가 덮어쓰이지 않도록 하는 잠금 매커니즘이 없습니다.
- 데이터 분리 또는 세부 원본 범위 부재: localStorage는 단순히 문자열 객체일 뿐이며 데이터 분리가 없으며 사용자 데이터가 앱 데이터와 혼합됩니다. 동일 출처 정책을 사용하더라도 특정 도메인이나 서브도메인별로 데이터를 제한할 방법이 없습니다. 이로 인해 여러 도메인 간에 GDPR 기준을 충족시킬 때 중복된 작업이 발생할 수 있습니다.
- 그룹화된 트랜잭션 부재: localStorage는 데이터베이스 정의에 따른 트랜잭션이 없을 뿐만 아니라 작업을 그룹화할 수 있는 방법도 없습니다. 각 작업은 동기적이며 격리되지 않으며 잠금이 없습니다.
- 직렬화 주의사항: 많은 웹사이트가 localStorage 관리의 부재로 인해 고장난 상태에서 운영되고 있습니다. 이 아티클 작성 시점으로부터 작년에는 제가 고객으로서 3개의 다른 웹 서비스로부터 “캐시를 지우세요”라는 답변을 받은 적이 있었는데, 이는 부적절한 localStorage 관리로 인한 것이었습니다. localStorage에 데이터를 저장할 때 주의사항을 알지 못하면 응용 프로그램에서 결코 마주치지 못할 버그를 생성할 수 있습니다. 특히 새로운 개발자들에게는 이러한 유형의 오류가 항상 명확하지 않을 수 있습니다.
- 구조화된 데이터 부재: JavaScript에는 ‘구조화된 복제 알고리즘’이라는 개념이 있습니다. 이것이 실제로 존재한다는 것을 알고 있어야 합니다. 현대 API 및 업데이트된 API인 postMessage, WebWorkers, IndexedDB, Caches API, BroadcastChannel, Channel Messaging API, MessagePort 및 History API는 모두 구조화된 데이터를 사용합니다. 이는 앱 내에서 JSON을 직렬화하고 역직렬화하는 문제를 해결합니다. localStorage는 이 기능으로 업데이트되지 않았으며 미래에 이에 대한 논의가 없습니다.
- 동기식 차단 작업: localStorage는 비동기가 아니며 주 스레드를 차단할 수있습니다. 읽기/쓰기 양과 빈도에 따라 애니메이션을 버벅거리게 만들 수도 있습니다. 특히 모바일 기기에서 유동적인 애플리케이션을 만들기 위해서는 비동기성이 기본적으로 필요합니다.
- 보안 절충사항: 명확히 하자면, 특별히 이를 위해 설계되지 않은 어떤 영구 저장소에도 민감한 데이터를 저장해서는 안됩니다. 개발자들은 여전히 localStorage에 세션 ID, JWT, 신용카드 세부정보 및 API 키를 일반적으로 저장합니다. 이는 window.localStorage 만큼 쉬우므로 매우 흔한 보안 위협입니다.
WebSQL은 어떻게 됐나요?
WebSQL는 웹 브라우저에서 SQL 기반 데이터베이스 API를 제공하기 위해 설계된 웹 개발 기술이었습니다. 이는 Web Database 사양의 일부로서 데이터를 구조화된 쿼리 언어(SQL) 인터페이스를 사용하여 클라이언트 측에 저장하는 것을 목표로 했습니다. WebSQL은 주로 브라우저에서 지원 되었지만, 결국 일부 도전적인 상황에 직면하여 폐기되게 되었습니다.
왜 WebSQL을 버렸을까?
- 단일 업체 구현: WebSQL은 주로 WebKit 기반 브라우저인 Chrome과 Safari에서 지원되었습니다. 그러나 다른 주요 브라우저 업체인 Mozilla와 Microsoft의 지원 부족으로 인해 개발자들의 채택은 상업적 세계에서 거의 없어진 것으로 보입니다.
- W3C 표준화 없음: 이는 채택에 매우 중요합니다. W3는 2010년에 제안을 철회한 것으로 보입니다.
- IndexedDB와의 경쟁: IndexedDB는 WebSQL이 부상하는 동안 더 많은 관심과 지원을 얻었습니다. WebSQL과 달리 IndexedDB는 표준 크로스 브라우저 솔루션으로 설계되었습니다.
- 보안 우려: 여러 개발자와 보안 전문가가 WebSQL의 안정성에 대해 우려를 표명했습니다. 그들은 권한 제어 부족 및 SQL 스타일 취약점을 포함한 다양한 측면에 회의적이었습니다.
결국 IndexedDB는 클라이언트측 스토리지에 대한 “권장" 표준이 되었으며, 더욱 강력하고 브라우저 간 친화적인 것으로 간주되었습니다. 하지만 이 글을 쓰는 시점에 대다수의 숙련된 프론트엔드 개발자들이 이를 전염병처럼 피했다면 “권장"이 무슨 소용이 있을까요?
단점에도 불구하고 당시 WebSQL은 웹 커뮤니티에서 높은 평가를 받았으며 가치 있는 경쟁자였습니다.
쿠키는 어떤가요?
쿠키는 Netscape Communications의 웹 브라우저 프로그래머인 Lou Montulli가 1994년에 만들었습니다.
몇몇 분들은 쿠키가 문제를 일으키기 시작할 때 심지어 아직 태어나지 않았을 것입니다. 이 기사의 제목은 “쿠키와 localStorage 사용 중단”이어야 할 것이지만, 이는 매우 어려운 싸움이죠. (네, 안전한 쿠키를 사용해야 합니다.)
- 크기 제한: 쿠키는 일반적으로 도메인당 약 4KB로 제한됩니다.
- 모든 요청과 함께 전송되는 데이터: 쿠키는 연결된 도메인에 대한 모든 HTTP 요청과 함께 전송됩니다. 요청이 있을 때마다 데이터를 전송할 필요가 없으면 불필요한 오버헤드가 발생하고 대역폭 사용량이 증가할 수 있습니다.
- 보안 우려: 쿠키는 XSS에 더 취약합니다. 쿠키는 도메인에 대한 모든 요청에 자동으로 포함되므로 악성 스크립트의 표적이 될 수 있습니다.
- 만료 및 수명: 쿠키는 지정된 날짜까지 만료되도록 설계되었습니다.
- 대기 시간 증가: 쿠키는 도메인에 대한 모든 HTTP 요청에 자동으로 포함되므로 일반적으로 대기 시간이 늘어나 웹 사이트 로드 속도가 느려집니다.
왜 IndexedDB 인가요?
- 더 나은 성능: localStorage와 달리 IndexedDB는 비동기식으로 작동하여 차단 작업을 방지합니다. (API는 Promise 기반이 아닌 이벤트 기반입니다.)
- 충분한 저장소 할당량: IndexedDB는 localStorage의 5MB 한도에 비해 더 큰 저장소 할당량(브라우저, OS 및 사용 가능한 저장소에 따라 다름)을 제공합니다.
- 신뢰성 및 구조화된 데이터: localStorage에 데이터를 저장하고 검색하는 것은 제대로 처리되지 않으면 예측할 수 없는 결과를 초래할 수 있습니다. IndexedDB는 일반적인 형 변환을 줄이고 구조화된 클론 알고리즘을 채택하여 데이터 무결성을 보장하여 이러한 문제를 완화합니다.
아마도 IndexedDB를 직접 사용하고 싶지 않을 것입니다.
이건 정말로 즐거운 일이 아니며, 예상했던 대로 되지 않아 실망하게 될 뿐만 아니라 적대적인 저장소와 싸우는 데 시간을 보낼 여유가 없을 것입니다.
라이브러리를 사용하려는 이유는 대부분 다음과 같습니다.
- 약속을 기반으로 한다.
- 사용하기 쉽다.
- 보일러플레이트 코드를 줄인다.
- 더 의미 있는 작업에 집중할 수 있다.
10KB gzip으로 압축된 것보다 큰 라이브러리를 사용하는 것을 추천하지 않습니다. 이러한 KB들이 누적되고 50KB 이상의 라이브러리는 현실적인 시나리오에서는 의미 있는 일을 수행하지 않습니다.
대부분의 IndexedDB 라이브러리에서 발견한 한 가지 문제는 버전 관리를 주로 지향한다는 것인데, 아마도 전혀 필요하지 않을 것입니다. 특히 합리적인 localStorage 대안을 찾고 있다면 더욱 그렇습니다.
Quick plug: 저는 IndexedDB의 보다 상대적인 측면에 초점을 맞추기 위해 라이브러리인 db64를 만들었습니다.
버전 관리나 커서가 필요하다면, 모든 특수한 경우를 잘 다루는 포괄적인 라이브러리인 idb를 추천합니다.
결론
내 의견으로는 지금 시대에는 누구도 localStorage를 사용하지 말아야 합니다. 새로운 개발자들은 Promise() 또는 async/await를 사용하는 것이 그들의 조건문을 참으로 만드는 이유를 이해하는 것보다 더 나은 경험을 할 것입니다.
요약하면 속도 이점이 있으며 논블로킹(non-blocking)이며 안정적으로 유형을 저장할 수 있으며 필요하다면 커서를 사용하여 항목을 반복할 수 있습니다. 그러한 유형의 작업에 관심이 있다면 로컬 스토리지가 차단되고 간섭되어 애니메이션을 방해하는 것과 달리 누적된 데이터 가져오기로 클라이언트 측 검색 엔진을 쉽게 구축할 수 있습니다. 👀
(Update: IndexedDB는 일반적으로 “낮은 수준"으로 설명됩니다. IndexedDB에는 전혀 낮은 수준이 없습니다. 단지 구식이고 친숙하지 않은 구문을 사용하는 API일 뿐입니다. 그러나 기본 기능이 부정되지는 않으므로 일반적인 라이브러리 사용이 가능합니다.)
영구 저장소의 경우 IndexedDB가 작업에 더 좋은 도구입니다. 당신이 원하지 않는 한 반드시 API를 배우거나 직접 사용할 필요는 없지만 작은 래퍼 라이브러리를 사용하여 삶을 더 쉽게 만드는 것이 합리적입니다.
읽어주셔서 감사합니다 :)