Skip to content

Commit 9d028aa

Browse files
authored
lib: update js side of blob (#21)
1 parent 9ba4eb5 commit 9d028aa

File tree

3 files changed

+42
-107
lines changed

3 files changed

+42
-107
lines changed

lib/internal/blob.js

Lines changed: 32 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@ const {
66
MathMin,
77
ObjectDefineProperties,
88
ObjectDefineProperty,
9-
PromiseResolve,
109
PromiseReject,
11-
SafePromisePrototypeFinally,
1210
ReflectConstruct,
1311
RegExpPrototypeExec,
1412
RegExpPrototypeSymbolReplace,
@@ -22,7 +20,7 @@ const {
2220

2321
const {
2422
createBlob: _createBlob,
25-
FixedSizeBlobCopyJob,
23+
concat,
2624
getDataObject,
2725
} = internalBinding('blob');
2826

@@ -51,7 +49,6 @@ const {
5149
const { inspect } = require('internal/util/inspect');
5250

5351
const {
54-
AbortError,
5552
codes: {
5653
ERR_INVALID_ARG_TYPE,
5754
ERR_INVALID_ARG_VALUE,
@@ -66,13 +63,8 @@ const {
6663
} = require('internal/validators');
6764

6865
const kHandle = Symbol('kHandle');
69-
const kState = Symbol('kState');
70-
const kIndex = Symbol('kIndex');
7166
const kType = Symbol('kType');
7267
const kLength = Symbol('kLength');
73-
const kArrayBufferPromise = Symbol('kArrayBufferPromise');
74-
75-
const kMaxChunkSize = 65536;
7668

7769
const disallowedTypeCharacters = /[^\u{0020}-\u{007E}]/u;
7870

@@ -271,40 +263,23 @@ class Blob {
271263
if (!isBlob(this))
272264
return PromiseReject(new ERR_INVALID_THIS('Blob'));
273265

274-
// If there's already a promise in flight for the content,
275-
// reuse it, but only while it's in flight. After the cached
276-
// promise resolves it will be cleared, allowing it to be
277-
// garbage collected as soon as possible.
278-
if (this[kArrayBufferPromise])
279-
return this[kArrayBufferPromise];
280-
281-
const job = new FixedSizeBlobCopyJob(this[kHandle]);
282-
283-
const ret = job.run();
284-
285-
// If the job returns a value immediately, the ArrayBuffer
286-
// was generated synchronously and should just be returned
287-
// directly.
288-
if (ret !== undefined)
289-
return PromiseResolve(ret);
290-
291-
const {
292-
promise,
293-
resolve,
294-
reject,
295-
} = createDeferredPromise();
296-
297-
job.ondone = (err, ab) => {
298-
if (err !== undefined)
299-
return reject(new AbortError(undefined, { cause: err }));
300-
resolve(ab);
266+
const { promise, resolve } = createDeferredPromise();
267+
const reader = this[kHandle].getReader();
268+
const buffers = [];
269+
const readNext = () => {
270+
const result = reader.pull((status, buffer) => {
271+
if (status === -1) {
272+
// EOS, concat & resolve
273+
// buffer should be undefined here
274+
resolve(concat(buffers));
275+
return;
276+
}
277+
buffers.push(buffer);
278+
readNext();
279+
});
301280
};
302-
this[kArrayBufferPromise] =
303-
SafePromisePrototypeFinally(
304-
promise,
305-
() => this[kArrayBufferPromise] = undefined);
306-
307-
return this[kArrayBufferPromise];
281+
readNext();
282+
return promise;
308283
}
309284

310285
/**
@@ -326,22 +301,22 @@ class Blob {
326301
if (!isBlob(this))
327302
throw new ERR_INVALID_THIS('Blob');
328303

329-
const self = this;
304+
const reader = this[kHandle].getReader();
330305
return new lazyReadableStream({
331-
async start() {
332-
this[kState] = await self.arrayBuffer();
333-
this[kIndex] = 0;
334-
},
335-
336-
pull(controller) {
337-
if (this[kState].byteLength - this[kIndex] <= kMaxChunkSize) {
338-
controller.enqueue(new Uint8Array(this[kState], this[kIndex]));
339-
controller.close();
340-
this[kState] = undefined;
341-
} else {
342-
controller.enqueue(new Uint8Array(this[kState], this[kIndex], kMaxChunkSize));
343-
this[kIndex] += kMaxChunkSize;
344-
}
306+
#reader: reader,
307+
pull(c) {
308+
const { promise, resolve } = createDeferredPromise();
309+
reader.pull((status, buffer) => {
310+
if (status === 1) {
311+
// EOS
312+
c.close();
313+
resolve();
314+
return;
315+
}
316+
c.enqueue(new Uint8Array(buffer));
317+
resolve();
318+
});
319+
return promise;
345320
}
346321
});
347322
}

lib/internal/fs/promises.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ const {
2525
S_IFREG
2626
} = constants;
2727

28+
const { createBlobFromFileHandle } = internalBinding('blob');
29+
2830
const binding = internalBinding('fs');
2931
const { Buffer } = require('buffer');
3032

@@ -310,6 +312,14 @@ class FileHandle extends EventEmitterMixin(JSTransferable) {
310312
return new WriteStream(undefined, { ...options, fd: this });
311313
}
312314

315+
/**
316+
* @typedef {import('../blob').Blob} Blob
317+
* @returns {Blob}
318+
*/
319+
blob() {
320+
return createBlobFromFileHandle(this);
321+
}
322+
313323
[kTransfer]() {
314324
if (this[kClosePromise] || this[kRefs] > 1) {
315325
throw lazyDOMException('Cannot transfer FileHandle while in use',

src/node_blob.cc

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -37,56 +37,6 @@ using v8::Value;
3737

3838
namespace {
3939

40-
// TODO(@flakey5, @jasnell): Update the JavaScript side of blob...
41-
//
42-
// Within the JavaScript Blob object, the arrayBuffer() method will change significantly.
43-
// the pattern will be something like:
44-
//
45-
// const { createDeferredPromise } = require('internal/util');
46-
// const { concat, ...} = internalBinding('blob');
47-
//
48-
// function arrayBuffer() {
49-
// const { promise, resolve } = createDeferredPromise();
50-
// const reader = this.#buffer.getReader();
51-
// const buffers = [];
52-
// const readNext = () => {
53-
// const result = reader.pull((status, buffer) => {
54-
// if (status == -1) {
55-
// // EOS, concat and resolve.
56-
// // buffer should be undefined here.
57-
// resolve(concat(buffers));
58-
// return;
59-
// }
60-
// buffers.push(buffer);
61-
// readNext();
62-
// });
63-
// };
64-
// readNext(); // Starts the read loop
65-
// return promise;
66-
// }
67-
//
68-
// For the stream() method, the pattern will be something like:
69-
//
70-
// function stream() {
71-
// const reader = this.#buffer.getReader();
72-
// return new ReadableStream({
73-
// #reader = reader;
74-
// pull(c) {
75-
// const { promise, resolve } = createDeferredPromise();
76-
// reader.pull((status, buffer) => {
77-
// if (status === -1) { // EOS
78-
// c.close();
79-
// resolve();
80-
// return;
81-
// }
82-
// c.enqueue(new Uint8Array(buffer));
83-
// resolve();
84-
// });
85-
// return promise;
86-
// }
87-
// });
88-
// }
89-
9040
// Concatenate multiple ArrayBufferView/ArrayBuffers into a single ArrayBuffer.
9141
// This method treats all ArrayBufferView types the same.
9242
void Concat(const FunctionCallbackInfo<Value>& args) {

0 commit comments

Comments
 (0)