웹 플랫폼은 개발자에게 웹을 위해 미세 조정된 고성능 애플리케이션을 빌드하는 데 필요한 도구를 점점 더 많이 제공하고 있습니다. 특히 WebAssembly (Wasm)를 통해 빠르고 강력한 웹 애플리케이션의 문이 열렸으며, 이제 Emscripten과 같은 기술을 통해 개발자는 웹에서 검증된 코드를 재사용할 수 있습니다. 이러한 잠재력을 제대로 활용하려면 개발자가 스토리지와 관련해 동일한 성능과 유연성을 갖춰야 합니다.
이때 Storage Foundation API가 유용합니다. Storage Foundation API는 빠르고 독자적인 새로운 스토리지 API로, 성능이 뛰어난 데이터베이스를 구현하고 대용량 임시 파일을 적절하게 관리하는 등 많은 요청이 있었던 웹 사용 사례를 제공합니다. 이 새로운 인터페이스를 통해 개발자는 웹에 '자체 저장소를 가져올' 수 있으므로 웹 코드와 플랫폼별 코드 간의 기능 격차를 줄일 수 있습니다.
Storage Foundation API는 매우 기본적인 파일 시스템과 유사하게 설계되었으며, 상위 수준의 구성요소를 빌드할 수 있는 일반적이고 간단하며 성능이 뛰어난 프리미티브를 제공하여 개발자에게 유연성을 제공합니다. 애플리케이션은 필요에 따라 최고의 도구를 활용하여 사용성, 성능, 안정성 사이에서 적절한 균형을 찾을 수 있습니다.
웹에 다른 Storage API가 필요한 이유는 무엇인가요?
웹 플랫폼은 개발자를 위한 다양한 저장소 옵션을 제공하며 각 옵션은 특정 사용 사례를 염두에 두고 빌드됩니다.
- 이러한 옵션 중 일부는 쿠키 또는
sessionStorage
와localStorage
메커니즘으로 구성된 Web Storage API와 같이 극히 소량의 데이터만 저장할 수 있게 하므로 이 제안서와 명확하게 중복되지 않습니다. - File and Directory Entries API 또는 WebSQL과 같은 다른 옵션은 다양한 이유로 이미 지원 중단되었습니다.
- File System Access API에도 유사한 API 노출 영역이 있지만, 클라이언트의 파일 시스템과 상호작용하고 원본 또는 브라우저의 소유권을 벗어날 수 있는 데이터에 대한 액세스를 제공하는 데 사용됩니다. 이러한 다양한 초점은 더 엄격한 보안 고려사항과 높은 성능 비용을 수반합니다.
- IndexedDB API는 일부 Storage Foundation API 사용 사례에서 백엔드로 사용할 수 있습니다. 예를 들어 Emscripten에는 IndexedDB 기반 영구 파일 시스템인 IDBFS가 포함되어 있습니다. 하지만 IndexedDB는 기본적으로 키-값 저장소이므로 상당한 성능 제한이 있습니다. 또한 IndexedDB에서는 파일의 하위 섹션에 직접 액세스하는 것이 훨씬 더 어렵고 더 느립니다.
- 마지막으로 CacheStorage 인터페이스는 광범위하게 지원되며 웹 애플리케이션 리소스와 같은 대용량 데이터를 저장하는 데 적합하도록 조정되었지만 값을 변경할 수 없습니다.
Storage Foundation API는 애플리케이션 원본 내에 정의된 변경 가능한 대용량 파일의 성능 향상을 허용하여 이전 스토리지 옵션의 모든 격차를 메우기 위한 것입니다.
Storage Foundation API의 추천 사용 사례
이 API를 사용할 수 있는 사이트의 예는 다음과 같습니다.
- 대량의 동영상, 오디오 또는 이미지 데이터를 다루는 생산성 또는 창의성 앱 이러한 앱은 세그먼트를 메모리에 보관하는 대신 디스크에 오프로드할 수 있습니다.
- Wasm에서 액세스할 수 있는 영구 파일 시스템을 사용하고 IDBFS가 보장할 수 있는 것보다 더 많은 성능이 필요한 앱
Storage Foundation API란 무엇인가요?
API에는 두 가지 주요 부분이 있습니다.
- 파일 시스템 호출: 파일 및 파일 경로와 상호작용하는 기본 기능을 제공합니다.
- 파일 핸들: 기존 파일에 대한 읽기 및 쓰기 액세스 권한을 제공합니다.
파일 시스템 호출
Storage Foundation API에는 window
객체에 있고 여러 함수를 포함하는 새로운 객체 storageFoundation
가 도입되었습니다.
storageFoundation.open(name)
: 지정된 이름의 파일이 있는 경우 열고, 그렇지 않으면 새 파일을 만듭니다. 열린 파일로 확인되는 프로미스를 반환합니다.
storageFoundation.delete(name)
: 지정된 이름의 파일을 삭제합니다. 파일이 삭제될 때 확인되는 프로미스를 반환합니다.storageFoundation.rename(oldName, newName)
: 파일 이름을 이전 이름에서 새 이름으로 원자적으로 바꿉니다. 파일 이름이 변경될 때 확인되는 프로미스를 반환합니다.storageFoundation.getAll()
: 모든 기존 파일 이름의 배열로 확인되는 프로미스를 반환합니다.storageFoundation.requestCapacity(requestedCapacity)
: 현재 실행 컨텍스트에서 사용할 새 용량 (바이트 단위)을 요청합니다. 사용 가능한 남은 용량으로 해결되는 프로미스를 반환합니다.
storageFoundation.releaseCapacity(toBeReleasedCapacity)
: 현재 실행 컨텍스트에서 지정된 바이트 수를 해제하고 남은 용량으로 확인되는 프로미스를 반환합니다.storageFoundation.getRemainingCapacity()
: 현재 실행 컨텍스트에 사용할 수 있는 용량으로 확인되는 프로미스를 반환합니다.
파일 핸들
파일 작업은 다음 함수를 통해 이루어집니다.
NativeIOFile.close()
: 파일을 닫고 작업이 완료되면 해결되는 프로미스를 반환합니다.NativeIOFile.flush()
: 파일의 메모리 내 상태를 저장소 기기와 동기화 (플러시)하고 작업이 완료되면 확인되는 프로미스를 반환합니다.
NativeIOFile.getLength()
: 바이트 단위의 파일 길이로 확인되는 프로미스를 반환합니다.NativeIOFile.setLength(length)
: 파일의 길이를 바이트 단위로 설정하고 작업이 완료되면 확인되는 프로미스를 반환합니다. 새 길이가 현재 길이보다 작으면 파일의 끝부터 바이트가 삭제됩니다. 그렇지 않은 경우 파일은 값이 0인 바이트로 확장됩니다.NativeIOFile.read(buffer, offset)
: 주어진 버퍼의 전송 결과인 버퍼를 통해 지정된 오프셋에서 파일의 콘텐츠를 읽습니다. 버퍼는 분리된 상태로 유지됩니다. 전송된 버퍼 및 성공적으로 읽은 바이트 수가 포함된NativeIOReadResult
를 반환합니다.NativeIOReadResult
는 다음 두 항목으로 구성된 객체입니다.buffer
:read()
에 전달된 버퍼를 전송한 결과인ArrayBufferView
입니다. 소스 버퍼와 유형 및 길이가 동일합니다.readBytes
:buffer
에 성공적으로 읽은 바이트 수입니다. 오류가 발생하거나 읽기 범위가 파일의 끝을 넘는 경우에는 버퍼 크기보다 작을 수 있습니다. 읽기 범위가 파일의 끝을 벗어나면 0으로 설정됩니다.
NativeIOFile.write(buffer, offset)
: 지정된 버퍼의 콘텐츠를 지정된 오프셋에서 파일에 씁니다. 버퍼는 데이터가 작성되기 전에 전송되므로 분리된 상태로 유지됩니다. 전송된 버퍼 및 성공적으로 쓴 바이트 수가 포함된NativeIOWriteResult
를 반환합니다. 쓰기 범위가 길이를 초과하면 파일이 확장됩니다.NativeIOWriteResult
는 다음 두 항목으로 구성된 객체입니다.buffer
:write()
에 전달된 버퍼를 전송한 결과인ArrayBufferView
입니다. 소스 버퍼와 유형 및 길이가 동일합니다.writtenBytes
:buffer
에 성공적으로 쓴 바이트 수입니다. 이 크기는 오류가 발생하는 경우 버퍼 크기보다 작을 수 있습니다.
완성형 예시
위에서 소개한 개념을 보다 잘 이해할 수 있도록 Storage Foundation 파일의 수명 주기 중 다양한 단계를 안내하는 두 가지 완전한 예시를 소개합니다.
열기, 쓰기, 읽기, 닫기
// Open a file (creating it if needed).
const file = await storageFoundation.open('test_file');
try {
// Request 100 bytes of capacity for this context.
await storageFoundation.requestCapacity(100);
const writeBuffer = new Uint8Array([64, 65, 66]);
// Write the buffer at offset 0. After this operation, `result.buffer`
// contains the transferred buffer and `result.writtenBytes` is 3,
// the number of bytes written. `writeBuffer` is left detached.
let result = await file.write(writeBuffer, 0);
const readBuffer = new Uint8Array(3);
// Read at offset 1. `result.buffer` contains the transferred buffer,
// `result.readBytes` is 2, the number of bytes read. `readBuffer` is left
// detached.
result = await file.read(readBuffer, 1);
// `Uint8Array(3) [65, 66, 0]`
console.log(result.buffer);
} finally {
file.close();
}
열기, 나열, 삭제 중
// Open three different files (creating them if needed).
await storageFoundation.open('sunrise');
await storageFoundation.open('noon');
await storageFoundation.open('sunset');
// List all existing files.
// `["sunset", "sunrise", "noon"]`
await storageFoundation.getAll();
// Delete one of the three files.
await storageFoundation.delete('noon');
// List all remaining existing files.
// `["sunrise", "noon"]`
await storageFoundation.getAll();
데모
아래 삽입에서 Storage Foundation API 데모를 사용해 볼 수 있습니다. 파일을 만들고, 이름을 바꾸고, 파일에 쓰고, 읽기를 수행하고, 변경 시 업데이트를 요청한 가용 용량을 확인할 수 있습니다. Glitch에서 데모의 소스 코드를 확인할 수 있습니다.
보안 및 권한
Chromium팀은 사용자 제어, 투명성, 인체공학을 포함하여 강력한 웹 플랫폼 기능에 대한 액세스 제어에 정의된 핵심 원칙에 따라 Storage Foundation API를 설계하고 구현했습니다.
웹상의 다른 최신 Storage API와 동일한 패턴에 따라 Storage Foundation API에 대한 액세스는 출처에 제약을 받습니다. 즉, 출처는 자체 생성된 데이터에만 액세스할 수 있습니다. 또한 보안 컨텍스트로 제한됩니다
사용자 제어
저장용량 할당량은 디스크 공간에 대한 액세스 권한을 분산하고 악용을 방지하는 데 사용됩니다. 먼저 차지하려는 메모리를 요청해야 합니다. 다른 스토리지 API와 마찬가지로 사용자는 브라우저를 통해 Storage Foundation API가 차지하는 공간을 비울 수 있습니다.
유용한 링크
- 공개 설명
- Storage Foundation API 데모 | Storage Foundation API 데모 소스
- Chromium 추적 버그
- ChromeStatus.com 항목
- 깜박임 구성요소:
Blink>Storage>NativeIO
- TAG 검토
- 프로토타입 대상
- WebKit 스레드
- Mozilla 스레드
감사의 말씀
Storage Foundation API는 Emanuel Krivoy와 Richard Stotz가 지정하고 구현했습니다. 이 문서는 피트 르페이지와 조 메들리가 검토했습니다.
Unsplash에서 Markus Spiske를 통한 히어로 이미지