| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 223494c commit df37c10
13 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -287,6 +287,119 @@ for (const b of buf) { | |||
| 287 | 287 | Additionally, the [`buf.values()`][], [`buf.keys()`][], and | |
| 288 | 288 | [`buf.entries()`][] methods can be used to create iterators. | |
| 289 | 289 | ||
| 290 | + ## Class: `Blob` | ||
| 291 | + <!-- YAML | ||
| 292 | + added: REPLACEME | ||
| 293 | + --> | ||
| 294 | + | ||
| 295 | + > Stability: 1 - Experimental | ||
| 296 | + | ||
| 297 | + A [`Blob`][] encapsulates immutable, raw data that can be safely shared across | ||
| 298 | + multiple worker threads. | ||
| 299 | + | ||
| 300 | + ### `new buffer.Blob([sources[, options]])` | ||
| 301 | + <!-- YAML | ||
| 302 | + added: REPLACEME | ||
| 303 | + --> | ||
| 304 | + | ||
| 305 | + * `sources` {string[]|ArrayBuffer[]|TypedArray[]|DataView[]|Blob[]} An array | ||
| 306 | + of string, {ArrayBuffer}, {TypedArray}, {DataView}, or {Blob} objects, or | ||
| 307 | + any mix of such objects, that will be stored within the `Blob`. | ||
| 308 | + * `options` {Object} | ||
| 309 | + * `encoding` {string} The character encoding to use for string sources. | ||
| 310 | + **Default**: `'utf8'`. | ||
| 311 | + * `type` {string} The Blob content-type. The intent is for `type` to convey | ||
| 312 | + the MIME media type of the data, however no validation of the type format | ||
| 313 | + is performed. | ||
| 314 | + | ||
| 315 | + Creates a new `Blob` object containing a concatenation of the given sources. | ||
| 316 | + | ||
| 317 | + {ArrayBuffer}, {TypedArray}, {DataView}, and {Buffer} sources are copied into | ||
| 318 | + the 'Blob' and can therefore be safely modified after the 'Blob' is created. | ||
| 319 | + | ||
| 320 | + String sources are also copied into the `Blob`. | ||
| 321 | + | ||
| 322 | + ### `blob.arrayBuffer()` | ||
| 323 | + <!-- YAML | ||
| 324 | + added: REPLACEME | ||
| 325 | + --> | ||
| 326 | + | ||
| 327 | + * Returns: {Promise} | ||
| 328 | + | ||
| 329 | + Returns a promise that fulfills with an {ArrayBuffer} containing a copy of | ||
| 330 | + the `Blob` data. | ||
| 331 | + | ||
| 332 | + ### `blob.size` | ||
| 333 | + <!-- YAML | ||
| 334 | + added: REPLACEME | ||
| 335 | + --> | ||
| 336 | + | ||
| 337 | + The total size of the `Blob` in bytes. | ||
| 338 | + | ||
| 339 | + ### `blob.slice([start, [end, [type]]])` | ||
| 340 | + <!-- YAML | ||
| 341 | + added: REPLACEME | ||
| 342 | + --> | ||
| 343 | + | ||
| 344 | + * `start` {number} The starting index. | ||
| 345 | + * `end` {number} The ending index. | ||
| 346 | + * `type` {string} The content-type for the new `Blob` | ||
| 347 | + | ||
| 348 | + Creates and returns a new `Blob` containing a subset of this `Blob` objects | ||
| 349 | + data. The original `Blob` is not alterered. | ||
| 350 | + | ||
| 351 | + ### `blob.text()` | ||
| 352 | + <!-- YAML | ||
| 353 | + added: REPLACEME | ||
| 354 | + --> | ||
| 355 | + | ||
| 356 | + * Returns: {Promise} | ||
| 357 | + | ||
| 358 | + Returns a promise that resolves the contents of the `Blob` decoded as a UTF-8 | ||
| 359 | + string. | ||
| 360 | + | ||
| 361 | + ### `blob.type` | ||
| 362 | + <!-- YAML | ||
| 363 | + added: REPLACEME | ||
| 364 | + --> | ||
| 365 | + | ||
| 366 | + * Type: {string} | ||
| 367 | + | ||
| 368 | + The content-type of the `Blob`. | ||
| 369 | + | ||
| 370 | + ### `Blob` objects and `MessageChannel` | ||
| 371 | + | ||
| 372 | + Once a {Blob} object is created, it can be sent via `MessagePort` to multiple | ||
| 373 | + destinations without transfering or immediately copying the data. The data | ||
| 374 | + contained by the `Blob` is copied only when the `arrayBuffer()` or `text()` | ||
| 375 | + methods are called. | ||
| 376 | + | ||
| 377 | + ```js | ||
| 378 | + const { Blob } = require('buffer'); | ||
| 379 | + const blob = new Blob(['hello there']); | ||
| 380 | + const { setTimeout: delay } = require('timers/promises'); | ||
| 381 | + | ||
| 382 | + const mc1 = new MessageChannel(); | ||
| 383 | + const mc2 = new MessageChannel(); | ||
| 384 | + | ||
| 385 | + mc1.port1.onmessage = async ({ data }) => { | ||
| 386 | + console.log(await data.arrayBuffer()); | ||
| 387 | + mc1.port1.close(); | ||
| 388 | + }; | ||
| 389 | + | ||
| 390 | + mc2.port1.onmessage = async ({ data }) => { | ||
| 391 | + await delay(1000); | ||
| 392 | + console.log(await data.arrayBuffer()); | ||
| 393 | + mc2.port1.close(); | ||
| 394 | + }; | ||
| 395 | + | ||
| 396 | + mc1.port2.postMessage(blob); | ||
| 397 | + mc2.port2.postMessage(blob); | ||
| 398 | + | ||
| 399 | + // The Blob is still usable after posting. | ||
| 400 | + data.text().then(console.log); | ||
| 401 | + ``` | ||
| 402 | + | ||
| 290 | 403 | ## Class: `Buffer` | |
| 291 | 404 | ||
| 292 | 405 | The `Buffer` class is a global type for dealing with binary data directly. | |
@@ -3397,6 +3510,7 @@ introducing security vulnerabilities into an application. | |||
| 3397 | 3510 | [UTF-8]: https://en.wikipedia.org/wiki/UTF-8 | |
| 3398 | 3511 | [WHATWG Encoding Standard]: https://encoding.spec.whatwg.org/ | |
| 3399 | 3512 | [`ArrayBuffer`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer | |
| 3513 | + [`Blob`]: https://developer.mozilla.org/en-US/docs/Web/API/Blob | ||
| 3400 | 3514 | [`Buffer.alloc()`]: #buffer_static_method_buffer_alloc_size_fill_encoding | |
| 3401 | 3515 | [`Buffer.allocUnsafe()`]: #buffer_static_method_buffer_allocunsafe_size | |
| 3402 | 3516 | [`Buffer.allocUnsafeSlow()`]: #buffer_static_method_buffer_allocunsafeslow_size | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -116,6 +116,10 @@ const { | |||
| 116 | 116 | addBufferPrototypeMethods | |
| 117 | 117 | } = require('internal/buffer'); | |
| 118 | 118 | ||
| 119 | + const { | ||
| 120 | + Blob, | ||
| 121 | + } = require('internal/blob'); | ||
| 122 | + | ||
| 119 | 123 | FastBuffer.prototype.constructor = Buffer; | |
| 120 | 124 | Buffer.prototype = FastBuffer.prototype; | |
| 121 | 125 | addBufferPrototypeMethods(Buffer.prototype); | |
@@ -1259,6 +1263,7 @@ function atob(input) { | |||
| 1259 | 1263 | } | |
| 1260 | 1264 | ||
| 1261 | 1265 | module.exports = { | |
| 1266 | + Blob, | ||
| 1262 | 1267 | Buffer, | |
| 1263 | 1268 | SlowBuffer, | |
| 1264 | 1269 | transcode, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,240 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + const { | ||
| 4 | + ArrayFrom, | ||
| 5 | + ObjectSetPrototypeOf, | ||
| 6 | + Promise, | ||
| 7 | + PromiseResolve, | ||
| 8 | + RegExpPrototypeTest, | ||
| 9 | + StringPrototypeToLowerCase, | ||
| 10 | + Symbol, | ||
| 11 | + SymbolIterator, | ||
| 12 | + Uint8Array, | ||
| 13 | + } = primordials; | ||
| 14 | + | ||
| 15 | + const { | ||
| 16 | + createBlob, | ||
| 17 | + FixedSizeBlobCopyJob, | ||
| 18 | + } = internalBinding('buffer'); | ||
| 19 | + | ||
| 20 | + const { TextDecoder } = require('internal/encoding'); | ||
| 21 | + | ||
| 22 | + const { | ||
| 23 | + JSTransferable, | ||
| 24 | + kClone, | ||
| 25 | + kDeserialize, | ||
| 26 | + } = require('internal/worker/js_transferable'); | ||
| 27 | + | ||
| 28 | + const { | ||
| 29 | + isAnyArrayBuffer, | ||
| 30 | + isArrayBufferView, | ||
| 31 | + } = require('internal/util/types'); | ||
| 32 | + | ||
| 33 | + const { | ||
| 34 | + customInspectSymbol: kInspect, | ||
| 35 | + emitExperimentalWarning, | ||
| 36 | + } = require('internal/util'); | ||
| 37 | + const { inspect } = require('internal/util/inspect'); | ||
| 38 | + | ||
| 39 | + const { | ||
| 40 | + AbortError, | ||
| 41 | + codes: { | ||
| 42 | + ERR_INVALID_ARG_TYPE, | ||
| 43 | + ERR_BUFFER_TOO_LARGE, | ||
| 44 | + ERR_OUT_OF_RANGE, | ||
| 45 | + } | ||
| 46 | + } = require('internal/errors'); | ||
| 47 | + | ||
| 48 | + const { | ||
| 49 | + validateObject, | ||
| 50 | + validateString, | ||
| 51 | + validateUint32, | ||
| 52 | + isUint32, | ||
| 53 | + } = require('internal/validators'); | ||
| 54 | + | ||
| 55 | + const kHandle = Symbol('kHandle'); | ||
| 56 | + const kType = Symbol('kType'); | ||
| 57 | + const kLength = Symbol('kLength'); | ||
| 58 | + | ||
| 59 | + let Buffer; | ||
| 60 | + | ||
| 61 | + function deferred() { | ||
| 62 | + let res, rej; | ||
| 63 | + const promise = new Promise((resolve, reject) => { | ||
| 64 | + res = resolve; | ||
| 65 | + rej = reject; | ||
| 66 | + }); | ||
| 67 | + return { promise, resolve: res, reject: rej }; | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + function lazyBuffer() { | ||
| 71 | + if (Buffer === undefined) | ||
| 72 | + Buffer = require('buffer').Buffer; | ||
| 73 | + return Buffer; | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + function isBlob(object) { | ||
| 77 | + return object?.[kHandle] !== undefined; | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + function getSource(source, encoding) { | ||
| 81 | + if (isBlob(source)) | ||
| 82 | + return [source.size, source[kHandle]]; | ||
| 83 | + | ||
| 84 | + if (typeof source === 'string') { | ||
| 85 | + source = lazyBuffer().from(source, encoding); | ||
| 86 | + } else if (isAnyArrayBuffer(source)) { | ||
| 87 | + source = new Uint8Array(source); | ||
| 88 | + } else if (!isArrayBufferView(source)) { | ||
| 89 | + throw new ERR_INVALID_ARG_TYPE( | ||
| 90 | + 'source', | ||
| 91 | + [ | ||
| 92 | + 'string', | ||
| 93 | + 'ArrayBuffer', | ||
| 94 | + 'SharedArrayBuffer', | ||
| 95 | + 'Buffer', | ||
| 96 | + 'TypedArray', | ||
| 97 | + 'DataView' | ||
| 98 | + ], | ||
| 99 | + source); | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + // We copy into a new Uint8Array because the underlying | ||
| 103 | + // BackingStores are going to be detached and owned by | ||
| 104 | + // the Blob. We also don't want to have to worry about | ||
| 105 | + // byte offsets. | ||
| 106 | + source = new Uint8Array(source); | ||
| 107 | + return [source.byteLength, source]; | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + class InternalBlob extends JSTransferable { | ||
| 111 | + constructor(handle, length, type = '') { | ||
| 112 | + super(); | ||
| 113 | + this[kHandle] = handle; | ||
| 114 | + this[kType] = type; | ||
| 115 | + this[kLength] = length; | ||
| 116 | + } | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + class Blob extends JSTransferable { | ||
| 120 | + constructor(sources = [], options) { | ||
| 121 | + emitExperimentalWarning('buffer.Blob'); | ||
| 122 | + if (sources === null || | ||
| 123 | + typeof sources[SymbolIterator] !== 'function' || | ||
| 124 | + typeof sources === 'string') { | ||
| 125 | + throw new ERR_INVALID_ARG_TYPE('sources', 'Iterable', sources); | ||
| 126 | + } | ||
| 127 | + if (options !== undefined) | ||
| 128 | + validateObject(options, 'options'); | ||
| 129 | + const { | ||
| 130 | + encoding = 'utf8', | ||
| 131 | + type = '', | ||
| 132 | + } = { ...options }; | ||
| 133 | + | ||
| 134 | + let length = 0; | ||
| 135 | + const sources_ = ArrayFrom(sources, (source) => { | ||
| 136 | + const { 0: len, 1: src } = getSource(source, encoding); | ||
| 137 | + length += len; | ||
| 138 | + return src; | ||
| 139 | + }); | ||
| 140 | + | ||
| 141 | + // This is a MIME media type but we're not actively checking the syntax. | ||
| 142 | + // But, to be fair, neither does Chrome. | ||
| 143 | + validateString(type, 'options.type'); | ||
| 144 | + | ||
| 145 | + if (!isUint32(length)) | ||
| 146 | + throw new ERR_BUFFER_TOO_LARGE(0xFFFFFFFF); | ||
| 147 | + | ||
| 148 | + super(); | ||
| 149 | + this[kHandle] = createBlob(sources_, length); | ||
| 150 | + this[kLength] = length; | ||
| 151 | + this[kType] = RegExpPrototypeTest(/[^\u{0020}-\u{007E}]/u, type) ? | ||
| 152 | + '' : StringPrototypeToLowerCase(type); | ||
| 153 | + } | ||
| 154 | + | ||
| 155 | + [kInspect](depth, options) { | ||
| 156 | + if (depth < 0) | ||
| 157 | + return this; | ||
| 158 | + | ||
| 159 | + const opts = { | ||
| 160 | + ...options, | ||
| 161 | + depth: options.depth == null ? null : options.depth - 1 | ||
| 162 | + }; | ||
| 163 | + | ||
| 164 | + return `Blob ${inspect({ | ||
| 165 | + size: this.size, | ||
| 166 | + type: this.type, | ||
| 167 | + }, opts)}`; | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + [kClone]() { | ||
| 171 | + const handle = this[kHandle]; | ||
| 172 | + const type = this[kType]; | ||
| 173 | + const length = this[kLength]; | ||
| 174 | + return { | ||
| 175 | + data: { handle, type, length }, | ||
| 176 | + deserializeInfo: 'internal/blob:InternalBlob' | ||
| 177 | + }; | ||
| 178 | + } | ||
| 179 | + | ||
| 180 | + [kDeserialize]({ handle, type, length }) { | ||
| 181 | + this[kHandle] = handle; | ||
| 182 | + this[kType] = type; | ||
| 183 | + this[kLength] = length; | ||
| 184 | + } | ||
| 185 | + | ||
| 186 | + get type() { return this[kType]; } | ||
| 187 | + | ||
| 188 | + get size() { return this[kLength]; } | ||
| 189 | + | ||
| 190 | + slice(start = 0, end = (this[kLength]), type = this[kType]) { | ||
| 191 | + validateUint32(start, 'start'); | ||
| 192 | + if (end < 0) end = this[kLength] + end; | ||
| 193 | + validateUint32(end, 'end'); | ||
| 194 | + validateString(type, 'type'); | ||
| 195 | + if (end < start) | ||
| 196 | + throw new ERR_OUT_OF_RANGE('end', 'greater than start', end); | ||
| 197 | + if (end > this[kLength]) | ||
| 198 | + throw new ERR_OUT_OF_RANGE('end', 'less than or equal to length', end); | ||
| 199 | + return new InternalBlob( | ||
| 200 | + this[kHandle].slice(start, end), | ||
| 201 | + end - start, type); | ||
| 202 | + } | ||
| 203 | + | ||
| 204 | + async arrayBuffer() { | ||
| 205 | + const job = new FixedSizeBlobCopyJob(this[kHandle]); | ||
| 206 | + | ||
| 207 | + const ret = job.run(); | ||
| 208 | + if (ret !== undefined) | ||
| 209 | + return PromiseResolve(ret); | ||
| 210 | + | ||
| 211 | + const { | ||
| 212 | + promise, | ||
| 213 | + resolve, | ||
| 214 | + reject | ||
| 215 | + } = deferred(); | ||
| 216 | + job.ondone = (err, ab) => { | ||
| 217 | + if (err !== undefined) | ||
| 218 | + return reject(new AbortError()); | ||
| 219 | + resolve(ab); | ||
| 220 | + }; | ||
| 221 | + | ||
| 222 | + return promise; | ||
| 223 | + } | ||
| 224 | + | ||
| 225 | + async text() { | ||
| 226 | + const dec = new TextDecoder(); | ||
| 227 | + return dec.decode(await this.arrayBuffer()); | ||
| 228 | + } | ||
| 229 | + } | ||
| 230 | + | ||
| 231 | + InternalBlob.prototype.constructor = Blob; | ||
| 232 | + ObjectSetPrototypeOf( | ||
| 233 | + InternalBlob.prototype, | ||
| 234 | + Blob.prototype); | ||
| 235 | + | ||
| 236 | + module.exports = { | ||
| 237 | + Blob, | ||
| 238 | + InternalBlob, | ||
| 239 | + isBlob, | ||
| 240 | + }; | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments