Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(432)

Side by Side Diff: Source/core/streams/ReadableStream.js

Issue 1118673002: Implement ReadableStream as a V8 extra (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Cleanups; make controller a member instead of arg Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 (function(global, builtins) {
2 'use strict';
3
4 // V8 "Imports":
5 // - %CreatePrivateOwnSymbol
6 // - %_CallFunction
7 // - %AddNamedProperty
8 // - %HasOwnProperty
9 // - $promiseThen, $promiseCreate, $promiseResolve, $promiseReject
10 // - InternalPackedArray
11
12 const readableStreamClosedPromise = %CreatePrivateOwnSymbol('[[closedPromise ]]');
13 const readableStreamCloseRequested = %CreatePrivateOwnSymbol('[[closeRequest ed]]');
14 const readableStreamController = %CreatePrivateOwnSymbol('[[controller]]');
15 const readableStreamPullAgain = %CreatePrivateOwnSymbol('[[pullAgain]]');
16 const readableStreamPulling = %CreatePrivateOwnSymbol('[[pulling]]');
17 const readableStreamQueue = %CreatePrivateOwnSymbol('[[queue]]');
18 const readableStreamQueueSize = %CreatePrivateOwnSymbol('[[queue]] total siz e');
19 const readableStreamReader = %CreatePrivateOwnSymbol('[[reader]]');
20 const readableStreamStarted = %CreatePrivateOwnSymbol('[[started]]');
21 const readableStreamState = %CreatePrivateOwnSymbol('[[state]]');
22 const readableStreamStoredError = %CreatePrivateOwnSymbol('[[storedError]]') ;
23 const readableStreamStrategySize = %CreatePrivateOwnSymbol('[[strategySize]] ');
24 const readableStreamStrategyHWM = %CreatePrivateOwnSymbol('[[strategyHWM]]') ;
25 const readableStreamUnderlyingSource = %CreatePrivateOwnSymbol('[[underlying Source]]');
26
27 const readableStreamControllerControlledReadableStream = %CreatePrivateOwnSy mbol('[[controlledReadableStream]]');
28
29 const readableStreamReaderClosedPromise = %CreatePrivateOwnSymbol('[[closedP romise]]');
30 const readableStreamReaderOwnerReadableStream = %CreatePrivateOwnSymbol('[[o wnerReadableStream]]');
31 const readableStreamReaderReadRequests = %CreatePrivateOwnSymbol('[[readRequ ests]]');
32 const readableStreamReaderState = %CreatePrivateOwnSymbol('[[state]]');
33 const readableStreamReaderStoredError = %CreatePrivateOwnSymbol('[[storedErr or]]');
34
35 const createWithExternalControllerSentinel = %CreatePrivateOwnSymbol(
36 'flag for UA-controlled ReadableStreams to pass');
37
38 const undefined = void 0;
39 const DONT_ENUM = 2;
40
41 const TypeError = global.TypeError;
42 const RangeError = global.RangeError;
43 const Promise = global.Promise;
44
45 const Number = global.Number;
46 const Number_isNaN = global.Number.isNaN;
47 const Number_isFinite = global.Number.isFinite;
48
49 const InternalPackedArray = builtins.InternalPackedArray;
50
51 function thenPromise(promise, f, r) {
52 return %_CallFunction(promise, f, r, $promiseThen);
53 }
54
55 // Manually create "bound" versions since Function.prototype.bind is slow.
56 const Promise_resolve = (function() {
57 const unbound = Promise.resolve;
58 return function(x) {
59 return %_CallFunction(Promise, x, unbound);
60 };
61 })();
62
63 const Promise_reject = (function() {
64 const unbound = Promise.reject;
65 return function(r) {
66 return %_CallFunction(Promise, r, unbound);
67 };
68 })();
69
70 class ReadableStream {
71 constructor(underlyingSource, strategy) {
72 if (underlyingSource === undefined) {
73 underlyingSource = {};
74 }
75 if (strategy === undefined) {
76 strategy = {};
77 }
78 const size = strategy.size;
79 let highWaterMark = strategy.highWaterMark;
80 if (highWaterMark === undefined) {
81 highWaterMark = 1;
82 }
83
84 const normalizedStrategy = ValidateAndNormalizeQueuingStrategy(size, highWaterMark);
85
86 this[readableStreamUnderlyingSource] = underlyingSource;
87
88 this[readableStreamQueue] = new InternalPackedArray();
89 this[readableStreamQueueSize] = 0;
90
91 // TODO(domenic) consolidate booleans into a bit field?
92 // TODO(domenic) use integers for state? (or put in bit field?)
93 this[readableStreamState] = 'readable';
94 this[readableStreamStarted] = false;
95 this[readableStreamCloseRequested] = false;
96 this[readableStreamPulling] = false;
97 this[readableStreamPullAgain] = false;
98 this[readableStreamReader] = undefined;
99
100 this[readableStreamStoredError] = undefined;
101 this[readableStreamStrategySize] = normalizedStrategy.size;
102 this[readableStreamStrategyHWM] = normalizedStrategy.highWaterMark;
103
104 // Avoid allocating a controller if the stream is going to be contro lled externally (i.e. from C++) anyway.
105 // All calls to underlyingSource methods will disregard their contro ller argument in such situations
106 // (but see below).
107 const controller = arguments[2] === createWithExternalControllerSent inel ?
108 null :
109 new ReadableStreamController(this);
110 this[readableStreamController] = controller;
111
112 // We need to pass ourself to the underlyingSource start method for externally-controlled streams. We
113 // use the now-useless controller argument to do so.
114 const argToStart = arguments[2] === createWithExternalControllerSent inel ? this : controller;
115
116 const that = this;
117 const startResult = CallOrNoop(underlyingSource, 'start', argToStart , 'underlyingSource.start');
118 thenPromise(Promise_resolve(startResult),
119 function() {
120 that[readableStreamStarted] = true;
121 RequestReadableStreamPull(that);
122 },
123 function(r) {
124 if (that[readableStreamState] === 'readable') {
125 return ErrorReadableStream(that, r);
126 }
127 }
128 );
129 }
130
131 cancel(reason) {
132 if (IsReadableStream(this) === false) {
133 return Promise_reject(new TypeError(
134 'ReadableStream.prototype.cancel can only be used on a Reada bleStream'));
135 }
136
137 if (IsReadableStreamLocked(this) === true) {
138 return Promise_reject(new TypeError(
139 'Cannot cancel a stream that already has a reader'));
140 }
141
142 return CancelReadableStream(this, reason);
143 }
144
145 getReader() {
146 if (IsReadableStream(this) === false) {
147 throw new TypeError('ReadableStream.prototype.getReader can only be used on a ReadableStream');
148 }
149
150 return AcquireReadableStreamReader(this);
151 }
152
153 tee() {
154 if (IsReadableStream(this) === false) {
155 throw new TypeError('ReadableStream.prototype.tee can only be us ed on a ReadableStream');
156 }
157
158 return TeeReadableStream(this);
159 }
160 }
161
162 class ReadableStreamController {
163 constructor(stream) {
164 if (IsReadableStream(stream) === false) {
165 throw new TypeError('ReadableStreamController can only be constr ucted with a ReadableStream instance');
166 }
167
168 if (stream[readableStreamController] !== undefined) {
169 throw new TypeError(
170 'ReadableStreamController instances can only be created by t he ReadableStream constructor');
171 }
172
173 this[readableStreamControllerControlledReadableStream] = stream;
174 }
175
176 get desiredSize() {
177 if (IsReadableStreamController(this) === false) {
178 throw new TypeError(
179 'ReadableStreamController.prototype.desiredSize can only be used on a ReadableStreamController');
180 }
181
182 return GetReadableStreamDesiredSize(this[readableStreamControllerCon trolledReadableStream]);
183 }
184
185 close() {
186 if (IsReadableStreamController(this) === false) {
187 throw new TypeError(
188 'ReadableStreamController.prototype.close can only be used o n a ReadableStreamController');
189 }
190
191 const stream = this[readableStreamControllerControlledReadableStream ];
192
193 if (stream[readableStreamCloseRequested] === true) {
194 throw new TypeError('The stream has already been closed; do not close it again!');
195 }
196 if (stream[readableStreamState] === 'errored') {
197 throw new TypeError('The stream is in an errored state and canno t be closed');
198 }
199
200 return CloseReadableStream(stream);
201 }
202
203 enqueue(chunk) {
204 if (IsReadableStreamController(this) === false) {
205 throw new TypeError(
206 'ReadableStreamController.prototype.enqueue can only be used on a ReadableStreamController');
207 }
208
209 const stream = this[readableStreamControllerControlledReadableStream ];
210
211 if (stream[readableStreamState] === 'errored') {
212 throw stream[readableStreamStoredError];
213 }
214
215 if (stream[readableStreamCloseRequested] === true) {
216 throw new TypeError('stream is closed or draining');
217 }
218
219 return EnqueueInReadableStream(stream, chunk);
220 }
221
222 error(e) {
223 if (IsReadableStreamController(this) === false) {
224 throw new TypeError(
225 'ReadableStreamController.prototype.error can only be used o n a ReadableStreamController');
226 }
227
228 const stream = this[readableStreamControllerControlledReadableStream ];
229
230 const state = stream[readableStreamState];
231 if (state !== 'readable') {
232 throw new TypeError(`The stream is ${state} and so cannot be err ored`);
233 }
234
235 return ErrorReadableStream(stream, e);
236 }
237 }
238
239 class ReadableStreamReader {
240 constructor(stream) {
241 if (IsReadableStream(stream) === false) {
242 throw new TypeError('ReadableStreamReader can only be constructed with a ReadableStream instance');
243 }
244 if (IsReadableStreamLocked(stream) === true) {
245 throw new TypeError('This stream has already been locked for exclu sive reading by another reader');
246 }
247
248 stream[readableStreamReader] = this;
249 this[readableStreamReaderOwnerReadableStream] = stream;
250
251 // TODO(domenic): use integers for state?
252 this[readableStreamReaderState] = 'readable';
253 this[readableStreamReaderStoredError] = undefined;
254 this[readableStreamReaderReadRequests] = new InternalPackedArray();
255 this[readableStreamReaderClosedPromise] = $promiseCreate();
256
257 const streamState = stream[readableStreamState];
258 if (streamState === 'closed' || streamState === 'errored') {
259 ReleaseReadableStreamReader(this);
260 }
261 }
262
263 get closed() {
264 if (IsReadableStreamReader(this) === false) {
265 return Promise_reject(
266 new TypeError('ReadableStreamReader.prototype.closed can onl y be used on a ReadableStreamReader'));
267 }
268
269 return this[readableStreamReaderClosedPromise];
270 }
271
272 cancel(reason) {
273 if (IsReadableStreamReader(this) === false) {
274 return Promise_reject(
275 new TypeError('ReadableStreamReader.prototype.cancel can onl y be used on a ReadableStreamReader'));
276 }
277
278 const state = this[readableStreamReaderState];
279 if (state === 'closed') {
280 return Promise_resolve(undefined);
281 }
282
283 if (state === 'errored') {
284 return Promise_reject(this[readableStreamReaderStoredError]);
285 }
286
287 return CancelReadableStream(this[readableStreamReaderOwnerReadableSt ream], reason);
288 }
289
290 read() {
291 if (IsReadableStreamReader(this) === false) {
292 return Promise_reject(
293 new TypeError('ReadableStreamReader.prototype.read can only be used on a ReadableStreamReader'));
294 }
295
296 return ReadFromReadableStreamReader(this);
297 }
298
299 releaseLock() {
300 if (IsReadableStreamReader(this) === false) {
301 throw new TypeError(
302 'ReadableStreamReader.prototype.releaseLock can only be used on a ReadableStreamReader');
303 }
304
305 if (this[readableStreamReaderOwnerReadableStream] === undefined) {
306 return undefined;
307 }
308
309 if (this[readableStreamReaderReadRequests].length > 0) {
310 throw new TypeError(
311 'Tried to release a reader lock when that reader has pending read() calls un-settled');
312 }
313
314 return ReleaseReadableStreamReader(this);
315 }
316 }
317
318 //
319 // Readable stream abstract operations
320 //
321
322 function AcquireReadableStreamReader(stream) {
323 return new ReadableStreamReader(stream);
324 }
325
326 function CancelReadableStream(stream, reason) {
327 const state = stream[readableStreamState];
328 if (state === 'closed') {
329 return Promise_resolve(undefined);
330 }
331 if (state === 'errored') {
332 return Promise_reject(stream[readableStreamStoredError]);
333 }
334
335 stream[readableStreamQueue] = new InternalPackedArray();
336 FinishClosingReadableStream(stream);
337
338 const underlyingSource = stream[readableStreamUnderlyingSource];
339 const sourceCancelPromise = PromiseCallOrNoop(underlyingSource, 'cancel' , reason, 'underlyingSource.cancel');
340 return thenPromise(sourceCancelPromise, function() { return undefined; } );
341 }
342
343 function CloseReadableStream(stream) {
344 if (stream[readableStreamState] === 'closed') {
345 return undefined;
346 }
347
348 stream[readableStreamCloseRequested] = true;
349
350 if (stream[readableStreamQueue].length === 0) {
351 return FinishClosingReadableStream(stream);
352 }
353 }
354
355
356 function EnqueueInReadableStream(stream, chunk) {
357 if (stream[readableStreamState] === 'closed') {
358 return undefined;
359 }
360
361 if (IsReadableStreamLocked(stream) === true &&
362 stream[readableStreamReader][readableStreamReaderReadRequests].lengt h > 0) {
363 const readRequest = stream[readableStreamReader][readableStreamReade rReadRequests].shift();
364 $promiseResolve(readRequest, CreateIterResultObject(chunk, false));
365 } else {
366 let chunkSize = 1;
367
368 const strategySize = stream[readableStreamStrategySize];
369 if (strategySize !== undefined) {
370 try {
371 chunkSize = strategySize(chunk);
372 } catch (chunkSizeE) {
373 ErrorReadableStream(stream, chunkSizeE);
374 throw chunkSizeE;
375 }
376 }
377
378 try {
379 EnqueueValueWithSize(stream, chunk, chunkSize);
380 } catch (enqueueE) {
381 ErrorReadableStream(stream, enqueueE);
382 throw enqueueE;
383 }
384 }
385
386 RequestReadableStreamPull(stream);
387 }
388
389 function ErrorReadableStream(stream, e) {
390 stream[readableStreamQueue] = new InternalPackedArray();
391 stream[readableStreamStoredError] = e;
392 stream[readableStreamState] = 'errored';
393
394 if (IsReadableStreamLocked(stream) === true) {
395 return ReleaseReadableStreamReader(stream[readableStreamReader]);
396 }
397 }
398
399 function FinishClosingReadableStream(stream) {
400 stream[readableStreamState] = 'closed';
401
402 if (IsReadableStreamLocked(stream) === true) {
403 return ReleaseReadableStreamReader(stream[readableStreamReader]);
404 }
405 }
406
407 function GetReadableStreamDesiredSize(stream) {
408 const queueSize = GetTotalQueueSize(stream);
409 return stream[readableStreamStrategyHWM] - queueSize;
410 }
411
412 function IsReadableStream(x) {
413 return %HasOwnProperty(x, readableStreamUnderlyingSource);
414 }
415
416 function IsReadableStreamLocked(stream) {
417 return stream[readableStreamReader] !== undefined;
418 }
419
420 function IsReadableStreamController(x) {
421 return %HasOwnProperty(x, readableStreamControllerControlledReadableStre am);
422 }
423
424 function IsReadableStreamReader(x) {
425 return %HasOwnProperty(x, readableStreamReaderOwnerReadableStream);
426 }
427
428 function ReadFromReadableStreamReader(reader) {
429 const state = reader[readableStreamReaderState];
430 if (state === 'closed') {
431 return Promise_resolve(CreateIterResultObject(undefined, true));
432 }
433
434 if (state === 'errored') {
435 return Promise_reject(reader[readableStreamReaderStoredError]);
436 }
437
438 const ownerReadableStream = reader[readableStreamReaderOwnerReadableStre am];
439 const queue = ownerReadableStream[readableStreamQueue];
440 if (queue.length > 0) {
441 const chunk = DequeueValue(ownerReadableStream);
442
443 if (ownerReadableStream[readableStreamCloseRequested] === true && qu eue.length === 0) {
444 FinishClosingReadableStream(ownerReadableStream);
445 } else {
446 RequestReadableStreamPull(ownerReadableStream);
447 }
448
449 return Promise_resolve(CreateIterResultObject(chunk, false));
450 } else {
451 const readRequest = $promiseCreate();
452
453 reader[readableStreamReaderReadRequests].push(readRequest);
454 RequestReadableStreamPull(ownerReadableStream);
455 return readRequest;
456 }
457 }
458
459 function ReleaseReadableStreamReader(reader) {
460 const ownerReadableStream = reader[readableStreamReaderOwnerReadableStre am];
461 if (ownerReadableStream[readableStreamState] === 'errored') {
462 reader[readableStreamReaderState] = 'errored';
463
464 const e = ownerReadableStream[readableStreamStoredError];
465 reader[readableStreamReaderStoredError] = e;
466 $promiseReject(reader[readableStreamReaderClosedPromise], e);
467
468 const readRequests = reader[readableStreamReaderReadRequests];
469 for (let i = 0; i < readRequests.length; ++i) {
470 $promiseReject(readRequests[i], e);
471 }
472 } else {
473 reader[readableStreamReaderState] = 'closed';
474 $promiseResolve(reader[readableStreamReaderClosedPromise], undefined );
475
476 const readRequests = reader[readableStreamReaderReadRequests];
477 for (let i = 0; i < readRequests.length; ++i) {
478 $promiseResolve(readRequests[i], CreateIterResultObject(undefine d, true));
479 }
480 }
481
482 reader[readableStreamReaderReadRequests] = new InternalPackedArray();
483 ownerReadableStream[readableStreamReader] = undefined;
484 reader[readableStreamReaderOwnerReadableStream] = undefined;
485 }
486
487 function RequestReadableStreamPull(stream) {
488 const shouldPull = ShouldReadableStreamPull(stream);
489 if (shouldPull === false) {
490 return undefined;
491 }
492
493 if (stream[readableStreamPulling] === true) {
494 stream[readableStreamPullAgain] = true;
495 return undefined;
496 }
497
498 stream[readableStreamPulling] = true;
499
500 const underlyingSource = stream[readableStreamUnderlyingSource];
501 const controller = stream[readableStreamController];
502 const pullPromise = PromiseCallOrNoop(underlyingSource, 'pull', controll er, 'underlyingSource.pull');
503
504 thenPromise(pullPromise,
505 function() {
506 stream[readableStreamPulling] = false;
507
508 if (stream[readableStreamPullAgain] === true) {
509 stream[readableStreamPullAgain] = false;
510 return RequestReadableStreamPull(stream);
511 }
512 },
513 function(e) {
514 if (stream[readableStreamState] === 'readable') {
515 return ErrorReadableStream(stream, e);
516 }
517 }
518 );
519 }
520
521 function ShouldReadableStreamPull(stream) {
522 const state = stream[readableStreamState];
523 if (state === 'closed' || state === 'errored') {
524 return false;
525 }
526
527 if (stream[readableStreamCloseRequested] === true) {
528 return false;
529 }
530
531 if (stream[readableStreamStarted] === false) {
532 return false;
533 }
534
535 if (IsReadableStreamLocked(stream) === true) {
536 const reader = stream[readableStreamReader];
537 const readRequests = reader[readableStreamReaderReadRequests];
538 if (readRequests.length > 0) {
539 return true;
540 }
541 }
542
543 const desiredSize = GetReadableStreamDesiredSize(stream);
544 if (desiredSize > 0) {
545 return true;
546 }
547
548 return false;
549 }
550
551 // Potential future optimization: use class instances for the underlying sou rces, so that we don't re-create
552 // closures every time.
553
554 function TeeReadableStream(stream) { // shouldClone argument from spec not s upported yet
555 const reader = AcquireReadableStreamReader(stream);
556
557 let closedOrErrored = false;
558 let canceled1 = false;
559 let canceled2 = false;
560 let reason1;
561 let reason2;
562 let promise = $promiseCreate();
563
564 const branch1 = new ReadableStream({
565 pull,
566 cancel: cancel1
567 });
568
569 const branch2 = new ReadableStream({
570 pull,
571 cancel: cancel2
572 });
573
574 thenPromise(reader[readableStreamReaderClosedPromise], undefined, functi on (r) {
575 if (closedOrErrored === true) {
576 return;
577 }
578
579 ErrorReadableStream(branch1, r);
580 ErrorReadableStream(branch2, r);
581 closedOrErrored = true;
582 });
583
584 return [branch1, branch2];
585
586
587 function pull() {
588 return thenPromise(ReadFromReadableStreamReader(reader), function (r esult) {
589 const value = result.value;
590 const done = result.done;
591
592 if (done === true && closedOrErrored === false) {
593 CloseReadableStream(branch1);
594 CloseReadableStream(branch2);
595 closedOrErrored = true;
596 }
597
598 if (closedOrErrored === true) {
599 return;
600 }
601
602 if (canceled1 === false) {
603 EnqueueInReadableStream(branch1, value);
604 }
605
606 if (canceled2 === false) {
607 EnqueueInReadableStream(branch2, value);
608 }
609 });
610 }
611
612 function cancel1(reason) {
613 canceled1 = true;
614 reason1 = reason;
615
616 if (canceled2 === true) {
617 const compositeReason = [reason1, reason2];
618 const cancelResult = CancelReadableStream(stream, compositeReaso n);
619 $promiseResolve(promise, cancelResult);
620 }
621
622 return promise;
623 }
624
625 function cancel2(reason) {
626 canceled2 = true;
627 reason2 = reason;
628
629 if (canceled1 === true) {
630 const compositeReason = [reason1, reason2];
631 const cancelResult = CancelReadableStream(stream, compositeReaso n);
632 $promiseResolve(promise, cancelResult);
633 }
634
635 return promise;
636 }
637 }
638
639 //
640 // Queue-with-sizes
641 // Modified from taking the queue (as in the spec) to taking the stream, so we can modify the queue size alongside.
642 //
643
644 function DequeueValue(stream) {
645 const result = stream[readableStreamQueue].shift();
646 stream[readableStreamQueueSize] -= result.size;
647 return result.value;
648 }
649
650 function EnqueueValueWithSize(stream, value, size) {
651 size = Number(size);
652 if (!Number_isFinite(size)) {
653 throw new RangeError('size must be a finite, non-NaN number.');
654 }
655
656 stream[readableStreamQueueSize] += size;
657 stream[readableStreamQueue].push({ value, size });
658 }
659
660 function GetTotalQueueSize(stream) {
661 return stream[readableStreamQueueSize];
662 }
663
664 //
665 // Other helpers
666 //
667
668 function ValidateAndNormalizeQueuingStrategy(size, highWaterMark) {
669 if (size !== undefined && typeof size !== 'function') {
670 throw new TypeError('size property of a queuing strategy must be a f unction');
671 }
672
673 highWaterMark = Number(highWaterMark);
674 if (Number_isNaN(highWaterMark)) {
675 throw new TypeError('highWaterMark property of a queuing strategy mu st be convertible to a non-NaN number');
676 }
677 if (highWaterMark < 0) {
678 throw new RangeError('highWaterMark property of a queuing strategy m ust be nonnegative');
679 }
680
681 return { size, highWaterMark };
682 }
683
684 function CallOrNoop(O, P, arg, nameForError) { // Modified from InvokeOrNoo p in spec
685 const method = O[P];
686 if (method === undefined) {
687 return undefined;
688 }
689 if (typeof method !== 'function') {
690 throw new TypeError(`${nameForError} must be a function or undefined `);
691 }
692
693 return %_CallFunction(O, arg, method);
694 }
695
696
697 function PromiseCallOrNoop(O, P, arg, nameForError) { // Modified from Promi seInvokeOrNoop in spec
698 let method;
699 try {
700 method = O[P];
701 } catch (methodE) {
702 return Promise_reject(methodE);
703 }
704
705 if (method === undefined) {
706 return Promise_resolve(undefined);
707 }
708
709 if (typeof method !== 'function') {
710 return Promise_reject(`${nameForError} must be a function or undefin ed`);
711 }
712
713 try {
714 return Promise_resolve(%_CallFunction(O, arg, method));
715 } catch (e) {
716 return Promise_reject(e);
717 }
718 }
719
720 function CreateIterResultObject(value, done) {
721 return { value, done };
722 }
723
724
725 //
726 // Additions to the global
727 //
728
729 %AddNamedProperty(global, 'ReadableStream', ReadableStream, DONT_ENUM);
730
731 //
732 // Exports for Blink to use
733 //
734
735 extrasExports.ReadableStream = ReadableStream;
736 extrasExports.createWithExternalControllerSentinel = createWithExternalContr ollerSentinel;
737 extrasExports.ErrorReadableStream = ErrorReadableStream;
738 extrasExports.EnqueueInReadableStream = EnqueueInReadableStream;
739 extrasExports.CloseReadableStream = CloseReadableStream;
740 extrasExports.GetReadableStreamDesiredSize = GetReadableStreamDesiredSize;
741 });
OLDNEW
« no previous file with comments | « Source/core/streams/CountQueuingStrategy.js ('k') | Source/core/streams/ScriptQueuingStrategy.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698