Rev. 2.73

HTML 5에 명시된 'localStorage'는 클라이언트 로컬에 데이터를 저장하기 위한 전역 함수입니다. 여기에 저장된 데이터는 장시간 영구적으로 보관할 수 있으며, 오프라인인 경우에도 호출이 가능하다는 특징 때문에 Ajax 응답 결과물 또는 무리한 연산 결과물 등을 캐싱하거나 오프라인 환경을 고려한 데이터베이스 동기화 등 웹 애플리케이션의 성능 향상을 꾀하기 위한 목적으로 사용될 수 있습니다. 부가적으로 서버측 로드는 줄고 트래픽이 절감하는 효과도 발생합니다. 그래서 아래와 같은 스토리지 도우미를 작성했습니다.

/* Local Storage Helper Class */
var Storage = Class.create({
  initialize: function(name, options) {
    this.options = Object.extend({
      clearable: true, // automatically clear data if an error occurred
      delay: 2000, // save data to localStorage after the allotted time
      maximum: 5 // the maximum size in megabytes
    }, options);

    if (typeof localStorage == "undefined" && typeof globalStorage != "undefined")
      window.localStorage = globalStorage[location.hostname];
      this.localStorage = window.localStorage;
    // undefined localStorage if it doesn't already exist
    if (!this.localStorage) this.localStorage = {
        getItem: function(name) {
          this.data = window.name ? window.name.evalJSON() : {};
          return $H(this.data[name] || (this.data[name] = {})).toJSON();
        }, setItem: function(name, data) {
          this.data[name] = data.evalJSON();
          window.name = $H(this.data).toJSON();
        }, removeItem: function(name) {
          delete this.data[name];
          window.name = $H(this.data).toJSON();
        }
      };

    this.name = name || 'unnamed';
    this.data = this.get();
  },
  // get item from localStorage
  get: function() {
    try {
      return (this.localStorage.getItem(this.name) || '{}').toString().evalJSON();
    } catch(e) {
      this.options.clearable && this.set({});
    }
  },
  // set item to localStorage
  set: function(data) {
    if (data) this.data = data;
    this.timer && clearTimeout(this.timer);
    this.timer = setTimeout(function() {
      if (this.size(true) > this.options.maximum * 1048576) return;
      try {
        this.localStorage.setItem(this.name, $H(this.data).toJSON());
      } catch(e) {
        this.options.clearable && this.set({});
      }
    }.bind(this), this.options.delay)
  },
  // remove item
  remove: function(name) {
    this.localStorage.removeItem(name || this.name);
  },
  // remove all items
  clear: function() {
    if (!this.localStorage.length)
      window.name = '{}';
    else
      for (i = 0; i < this.localStorage.length; i++) this.remove(this.localStorage.key(i));
  },
  // size of localStorage
  size: function(bytes) {
    var data = $H(this.data).toJSON().length;
    return bytes ? data : data > 1024 ? (function() {
      data = (data / 1024).round().toString();
      var reg = /(^[+-]?\d+)(\d{3})/;
      while (reg.test(data)) data = data.replace(reg, '$1' + ',' + '$2');
      return data  + 'kb';
    })() : data + 'bytes';
  }
});

/* Usage */
var MyStorage = new Storage('MyStorage'); // Create the helper instance
var MyData = MyStorage.data; // Read data from localStorage(JSON Object)
MyData['firejune'] = { name: 'Junho, Kyung', age: 33 }; // Update a single data
MyStorage.set(MyData); // Write the data to localStorage
MyStorage.size(); // => '49bytes'

위 코드는 이 블로그의 이미지 프로세싱 결과동적인 자바스크립트 호출 결과에 실제로 반영되어 사용되고 있습니다. JSON 자료형으로 입/출력하며, JSON을 문자로 변환 보관하기 위해 json2.js 라이브러리를 필요로 합니다.(브라우저가 Native JSON을 지원하지 않는 경우)합니다. localStorage를 사용할 수 없는 브라우저인 경우에는 단기적으로 자료 보존이 가능한 'window.name' 프로퍼티에 저장하는 트릭을 사용합니다. 그리고 불필요한(비효율적인, 반복적인) 저장 호출들을 무시하기 위해 타이머(기본 2초)가 적용되어 있으며 옵션으로 타이머 시간값을 변경할 수 있습니다. 신기하게도 'localStorage.setItem'메서드로 자료가 입력되는 동시에 하드디스크를 '드르륵' 긁더라구요.

덧1. 문득 떠오른 뻘아이디어: 이렇게 모인 캐시들을 cometd를 이용해서 접속중인 모든 클라이언트에 전송하고 머지해 버리면 어떤 현상이 발생할까요? 이름하여 '미러링 캐시 이펙트'? ㅎㅎㅎ
덧2. 도메인당 최대 자료 저장량이 브라우저에 따라 다르므로 초기화가 자동으로 이루어질 수 있도록 옵션으로 제공 함(Firefox의 최대 저장량 5 MB)
덧3. window.name을 스토리지로 사용하는 경우에도 인스턴스 단위로 구분하여 저장 함
덧4. 해당 인스턴스의 스토리지 사용량을 반환하는 size() 메서드 추가
덧5. window.name을 스토리지로 사용하는 경우 지속적으로 초기화 되던 버그 수정
덧6. 인스턴스당 최대 저장량을 설정할 수 있도록 함(자동으로 초기화하지 않음)
덧7. 구글 크롬에서 발생하는 "localStorage is null" 오류 수정

Comments

tests.gif

Robert Nyman씨는 자바스크립트 버전별 특징들에 대한 브라우저 단위 테스트를 시행하고 그 결과를 일목요연하게 정리하여 공개하였습니다. 자바스크립트 1.6부터 1.8.1로 버전이 오르면서 지원하는 여러 기능들 그리고 Getters, Setters, DOM Storage, Native JSON 등의 지원여부를 알아내는 예제 코드와 브라우저별 실행 결과를 알기 쉽게 작성했습니다. 멋지네요!

Comments