Skip to content

Commit b6702af

Browse files
committed
lib: reduce overhead of blob clone
1 parent 78a1570 commit b6702af

File tree

3 files changed

+27
-12
lines changed

3 files changed

+27
-12
lines changed

benchmark/blob/clone.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,17 @@ const assert = require('assert');
77

88
const bench = common.createBenchmark(main, {
99
n: [50e3],
10+
bytes: [128, 1024, 1024 ** 2],
1011
});
1112

1213
let _cloneResult;
1314

14-
function main({ n }) {
15+
function main({ n, bytes }) {
16+
const buff = Buffer.allocUnsafe(bytes);
17+
const blob = new Blob(buff);
1518
bench.start();
1619
for (let i = 0; i < n; ++i)
17-
_cloneResult = structuredClone(new Blob(['hello']));
20+
_cloneResult = structuredClone(blob);
1821
bench.end(n);
1922

2023
// Avoid V8 deadcode (elimination)

lib/internal/blob.js

+12-10
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ class Blob {
200200
const length = this[kLength];
201201
return {
202202
data: { handle, type, length },
203-
deserializeInfo: 'internal/blob:ClonedBlob',
203+
deserializeInfo: 'internal/blob:CloneableBlob',
204204
};
205205
}
206206

@@ -397,25 +397,27 @@ class Blob {
397397
}
398398
}
399399

400-
function ClonedBlob() {
401-
return ReflectConstruct(function() {
400+
class CloneableBlob extends Blob {
401+
static {
402402
markTransferMode(this, true, false);
403-
}, [], Blob);
403+
this[kDeserialize] = () => {};
404+
}
404405
}
405-
ClonedBlob.prototype[kDeserialize] = () => {};
406406

407-
function TransferrableBlob(handle, length, type = '') {
407+
CloneableBlob.prototype.constructor = Blob;
408+
409+
function TransferableBlob(handle, length, type = '') {
408410
markTransferMode(this, true, false);
409411
this[kHandle] = handle;
410412
this[kType] = type;
411413
this[kLength] = length;
412414
}
413415

414-
ObjectSetPrototypeOf(TransferrableBlob.prototype, Blob.prototype);
415-
ObjectSetPrototypeOf(TransferrableBlob, Blob);
416+
ObjectSetPrototypeOf(TransferableBlob.prototype, Blob.prototype);
417+
ObjectSetPrototypeOf(TransferableBlob, Blob);
416418

417419
function createBlob(handle, length, type = '') {
418-
const transferredBlob = new TransferrableBlob(handle, length, type);
420+
const transferredBlob = new TransferableBlob(handle, length, type);
419421

420422
// Fix issues like: https://github.com/nodejs/node/pull/49730#discussion_r1331720053
421423
transferredBlob.constructor = Blob;
@@ -489,7 +491,7 @@ function createBlobFromFilePath(path, options) {
489491

490492
module.exports = {
491493
Blob,
492-
ClonedBlob,
494+
CloneableBlob,
493495
createBlob,
494496
createBlobFromFilePath,
495497
isBlob,

test/parallel/test-blob.js

+10
Original file line numberDiff line numberDiff line change
@@ -480,3 +480,13 @@ assert.throws(() => new Blob({}), {
480480
assert.ok(blob.slice(0, 1).constructor === Blob);
481481
assert.ok(blob.slice(0, 1) instanceof Blob);
482482
}
483+
484+
(async () => {
485+
const blob = new Blob(['hello']);
486+
487+
assert.ok(structuredClone(blob).constructor === Blob);
488+
assert.ok(structuredClone(blob) instanceof Blob);
489+
assert.ok(structuredClone(blob).size === blob.size);
490+
assert.ok(structuredClone(blob).size === blob.size);
491+
assert.ok((await structuredClone(blob).text()) === (await blob.text()));
492+
})().then(common.mustCall());

0 commit comments

Comments
 (0)