互換性を破る変更: AccessHandles の同期メソッド

送信元のプライベート ファイル システムは、ファイルのコンテンツへのインプレースかつ排他的な書き込みアクセス権を提供するなど、パフォーマンスを重視して最適化された特殊なファイルへのアクセスを提供します。デベロッパーは、FileSystemFileHandle オブジェクトで公開されるメソッドである createSyncAccessHandle() を呼び出すことで、このようなファイルにアクセスできます。この呼び出しにより FileSystemSyncAccessHandle が生成されます。

FileSystemSyncAccessHandle は、ローカル ファイルに対するパフォーマンスの高いアクセスを提供するファイル プリミティブです。その主なユースケースの一つは、C/C++ コードを Wasm に移植するアプリです。ただし、Wasm では非同期呼び出しが完全にはサポートされておらず、代わりに Asyncify ライブラリを使用するとパフォーマンスが大幅に低下します。FileSystemSyncAccessHandle のすべてのメソッドを同期的に POSIX に似たファイル API の Wasm ベースのアプリケーションと一致させることで、API をより人間工学的に使用できるようになり、パフォーマンスが大幅に向上します。

改良点

FileSystemSyncAccessHandle では、以下のメソッドが公開されます。以下のメソッドは、以前は非同期でしたが、Chromium 108 以降では同期的でした。

  • truncate(newSize): アクセス ハンドルに関連付けられたファイルを newSize バイトに変更します。newSize が現在のファイルサイズより大きい場合、ファイルは null バイトでパディングされます。そうでない場合、ファイルは切り捨てられます。
  • getSize(): アクセス ハンドルに関連付けられたファイルのサイズをバイト単位で返します。
  • flush(): アクセス ハンドルに関連付けられたファイルのコンテンツに、write() を通じて行われたすべての変更が含まれるようにします。
  • close(): アクセス ハンドルをフラッシュして閉じます。アクセス ハンドルを閉じると、そのハンドルに対する今後のオペレーションが無効になり、アクセス ハンドルに関連付けられたエントリのロックが解除されます。
// In a `Worker`:
const root = await navigator.storage.getDirectory();
const fileHandle = await root.getFileHandle('test', { create: true });
// `createSyncAccessHandle()` is still async.
const accessHandle = await fileHandle.createSyncAccessHandle();
// Both `read()` and `write()` were sync before.
accessHandle.read(/* ... */);
accessHandle.write(/* ... */);

// New: synchronous as of Chromium 108.
console.log(accessHandle.getSize());
accessHandle.truncate(123);
accessHandle.flush();
accessHandle.close();

必要なご対応

なお、メソッドを非同期から同期に変更することは、ウェブで公開される変更であり、破損する可能性があります。同期メソッドで await を使用しても何も起こりませんが、Promise.then() を使用すると失敗します。以前非同期になったメソッドの同期メソッドの結果に対して then() 呼び出しを連結する場合は、コードを変更する必要があります。

// (✅) This won't break, but you better remove the superfluous `await`:
await accessHandle.flush();
// ✅ Correct:
accessHandle.flush();
// ⛔️ This will break, and you need to restructure your code:
accessHandle.flush().then(/* Follow-up code */);
// ✅ Correct:
accessHandle.flush();
/* Follow-up code */