I’m appending data to a log file using OPFS (Origin Private File System browser API) and I noticed it’s very slow.
It takes ~22ms to write 5MB to a new file but it also takes ~23ms to append a single byte.
I didn’t file anything like an append flag. I had to read the file size and start writing at that position to append data. Is there a better way of appending data?
For comparison, in Node.js it takes 1.3ms to write 5MB to a new file and 0.1ms to append a single byte.
OPFS benchmark code:
(async () => {
async function create5MBFile(fileHandle) {
console.time('create5MBFile');
const writable = await fileHandle.createWritable();
const chunkSize = 5 * 1024 * 1024;
const chunk = new Uint8Array(chunkSize).fill(0);
await writable.write(chunk);
await writable.close();
console.timeEnd('create5MBFile');
}
async function appendByte(fileHandle) {
console.time('appendByte');
const file = await fileHandle.getFile();
const currentSize = file.size;
const writable = await fileHandle.createWritable({ keepExistingData: true });
const byteToAppend = new Uint8Array([0]);
await writable.write({ type: 'write', position: currentSize, data: byteToAppend });
await writable.close();
console.timeEnd('appendByte');
}
const root = await navigator.storage.getDirectory();
const fileHandle = await root.getFileHandle('append.log', { create: true });
await create5MBFile(fileHandle);
await appendByte(fileHandle);
})();
Node.js benchmark:
const fs = require('fs');
const path = require('path');
const filePath = path.join(__dirname, 'append.log');
const fileSize = 5 * 1024 * 1024;
const byteToAppend = Buffer.from([0]);
function create5MBFileSync() {
const fileBuffer = Buffer.alloc(fileSize, 0);
console.time('write 5MB');
fs.writeFileSync(filePath, fileBuffer);
console.timeEnd('write 5MB');
}
function appendByteSync() {
console.time('appendByteSync');
fs.appendFileSync(filePath, byteToAppend);
console.timeEnd('appendByteSync');
}
create5MBFileSync();
appendByteSync();