Skip to content

Commit

Permalink
lib: reduce overhead of blob clone
Browse files Browse the repository at this point in the history
PR-URL: #50110
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
  • Loading branch information
H4ad authored and targos committed Oct 23, 2023
1 parent bac872c commit b6021ab
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 16 deletions.
7 changes: 5 additions & 2 deletions benchmark/blob/clone.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@ const assert = require('assert');

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

let _cloneResult;

function main({ n }) {
function main({ n, bytes }) {
const buff = Buffer.allocUnsafe(bytes);
const blob = new Blob(buff);
bench.start();
for (let i = 0; i < n; ++i)
_cloneResult = structuredClone(new Blob(['hello']));
_cloneResult = structuredClone(blob);
bench.end(n);

// Avoid V8 deadcode (elimination)
Expand Down
19 changes: 5 additions & 14 deletions lib/internal/blob.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const {
ObjectDefineProperty,
ObjectSetPrototypeOf,
PromiseReject,
ReflectConstruct,
RegExpPrototypeExec,
RegExpPrototypeSymbolReplace,
StringPrototypeToLowerCase,
Expand Down Expand Up @@ -200,7 +199,7 @@ class Blob {
const length = this[kLength];
return {
data: { handle, type, length },
deserializeInfo: 'internal/blob:ClonedBlob',
deserializeInfo: 'internal/blob:Blob',
};
}

Expand Down Expand Up @@ -397,25 +396,18 @@ class Blob {
}
}

function ClonedBlob() {
return ReflectConstruct(function() {
markTransferMode(this, true, false);
}, [], Blob);
}
ClonedBlob.prototype[kDeserialize] = () => {};

function TransferrableBlob(handle, length, type = '') {
function TransferableBlob(handle, length, type = '') {
markTransferMode(this, true, false);
this[kHandle] = handle;
this[kType] = type;
this[kLength] = length;
}

ObjectSetPrototypeOf(TransferrableBlob.prototype, Blob.prototype);
ObjectSetPrototypeOf(TransferrableBlob, Blob);
ObjectSetPrototypeOf(TransferableBlob.prototype, Blob.prototype);
ObjectSetPrototypeOf(TransferableBlob, Blob);

function createBlob(handle, length, type = '') {
const transferredBlob = new TransferrableBlob(handle, length, type);
const transferredBlob = new TransferableBlob(handle, length, type);

// Fix issues like: https://github.com/nodejs/node/pull/49730#discussion_r1331720053
transferredBlob.constructor = Blob;
Expand Down Expand Up @@ -489,7 +481,6 @@ function createBlobFromFilePath(path, options) {

module.exports = {
Blob,
ClonedBlob,
createBlob,
createBlobFromFilePath,
isBlob,
Expand Down
10 changes: 10 additions & 0 deletions test/parallel/test-blob.js
Original file line number Diff line number Diff line change
Expand Up @@ -480,3 +480,13 @@ assert.throws(() => new Blob({}), {
assert.ok(blob.slice(0, 1).constructor === Blob);
assert.ok(blob.slice(0, 1) instanceof Blob);
}

(async () => {
const blob = new Blob(['hello']);

assert.ok(structuredClone(blob).constructor === Blob);
assert.ok(structuredClone(blob) instanceof Blob);
assert.ok(structuredClone(blob).size === blob.size);
assert.ok(structuredClone(blob).size === blob.size);
assert.ok((await structuredClone(blob).text()) === (await blob.text()));
})().then(common.mustCall());

0 comments on commit b6021ab

Please sign in to comment.