- From: Domenic Denicola <notifications@github.com>
- Date: Tue, 22 Nov 2016 15:25:25 -0800
- To: whatwg/streams <streams@noreply.github.com>
- Message-ID: <whatwg/streams/pull/619/review/9778349@github.com>
domenic commented on this pull request. > @@ -158,7 +162,6 @@ function WritableStreamError(stream, e) { } stream._state = 'errored'; Can we keep this line together with assigning storedError? It seems bad for them to get out of sync. > @@ -173,11 +176,26 @@ function WritableStreamFinishClose(stream) { defaultWriterClosedPromiseResolve(stream._writer); } -function WritableStreamFulfillWriteRequest(stream) { - assert(stream._writeRequests.length > 0); +function WritableStreamRejectUnresolvedPromises(stream) { + const state = stream._state; + assert(state === 'writable' || state === 'closing' || state === 'errored'); This assertion might be tightened if we move the state assignment as discussed above. > @@ -20,6 +20,12 @@ class WritableStream { // producer without waiting for the queued writes to finish. this._writeRequests = []; + // Write requests are removed from _writeRequests when write() is called on the underlying sink. This prevents + // them from being erroneously rejected on error. If a write() call is pending, the request is stored here. + this._pendingWriteRequest = undefined; + + this._pendingCloseRequest = undefined; I wonder if this could be consolidated with writer's closedPromise... > @@ -173,11 +176,26 @@ function WritableStreamFinishClose(stream) { defaultWriterClosedPromiseResolve(stream._writer); } -function WritableStreamFulfillWriteRequest(stream) { - assert(stream._writeRequests.length > 0); +function WritableStreamRejectUnresolvedPromises(stream) { I wonder if there's a better name for this that indicates clearly that it will reject write requests + pending close requests + writer closed promise, but not pending write requests. Also, can it maybe assert that there is no pending write request? > + const ws = new WritableStream({ + write() { + return flushAsyncEvents(); + } + }); + const writer = ws.getWriter(); + return writer.ready.then(() => { + const writePromise = writer.write('a'); + writer.abort(new Error()); + let closedResolved = false; + return Promise.all([ + writePromise.then(() => assert_false(closedResolved, '.closed should not resolve before write()')), + promise_rejects(t, new TypeError(), writer.closed, '.closed should reject') + .then(() => { + closedResolved = true; + })]); Style nit: I think this would be cleaner with `.then` on the preceding line and `]);` on its own line. > + return flushAsyncEvents(); + } + }); + const writer = ws.getWriter(); + return writer.ready.then(() => { + const writePromise = writer.write('a'); + writer.abort(new Error()); + let closedResolved = false; + return Promise.all([ + writePromise.then(() => assert_false(closedResolved, '.closed should not resolve before write()')), + promise_rejects(t, new TypeError(), writer.closed, '.closed should reject') + .then(() => { + closedResolved = true; + })]); + }); +}, '.closed should not resolve before write()'); before fulfilled write() > + const writePromise = writer.write('a'); + writer.abort(new Error()); + let closedResolved = false; + return Promise.all([ + writePromise.then(() => assert_false(closedResolved, '.closed should not resolve before write()')), + promise_rejects(t, new TypeError(), writer.closed, '.closed should reject') + .then(() => { + closedResolved = true; + })]); + }); +}, '.closed should not resolve before write()'); + +promise_test(t => { + const ws = new WritableStream({ + write() { + return Promise.reject(new Error()); Use `error1` here and below? > + +promise_test(t => { + const ws = new WritableStream({ + write() { + return Promise.reject(new Error()); + } + }); + const writer = ws.getWriter(); + return writer.ready.then(() => { + const writePromise = writer.write('a'); + writer.abort(new Error()); + let closedResolved = false; + return Promise.all([ + promise_rejects(t, new Error(), writePromise, 'write() should reject') + .then(() => assert_false(closedResolved, '.closed should not resolve before write()')), + promise_rejects(t, new TypeError(), writer.closed, '.closed should reject') Hmm. I think the write promise should get the first crack at determining how the stream errors, even if abort() has been called. I guess this is related to https://github.com/whatwg/streams/issues/617#issuecomment-262348791. > + writer.abort(new Error()); + let closedResolved = false; + return Promise.all([ + promise_rejects(t, new Error(), writePromise, 'write() should reject') + .then(() => assert_false(closedResolved, '.closed should not resolve before write()')), + promise_rejects(t, new TypeError(), writer.closed, '.closed should reject') + .then(() => { + closedResolved = true; + })]); + }); +}, '.closed should not resolve before rejected write()'); + +promise_test(t => { + const ws = new WritableStream({ + write() { + return delay(0); why not flushAsyncEvents? > + promise_rejects(t, new TypeError(), writer.closed, '.closed should reject') + .then(() => { + closedResolved = true; + })]); + }); +}, '.closed should not resolve before rejected write()'); + +promise_test(t => { + const ws = new WritableStream({ + write() { + return delay(0); + } + }, new CountQueuingStrategy(4)); + const writer = ws.getWriter(); + return writer.ready.then(() => { + const resolveOrder = []; settlementOrder > + const resolveOrder = []; + return Promise.all([ + writer.write('1').then(() => resolveOrder.push(1)), + promise_rejects(t, new TypeError(), writer.write('2'), 'first queued write should be rejected') + .then(() => resolveOrder.push(2)), + promise_rejects(t, new TypeError(), writer.write('3'), 'second queued write should be rejected') + .then(() => resolveOrder.push(3)), + writer.abort(new Error()) + ]).then(() => assert_array_equals([1, 2, 3], resolveOrder, 'writes should be satisfied in order')); + }); +}, 'writes should be satisfied in order when aborting'); + +promise_test(t => { + const ws = new WritableStream({ + write() { + return Promise.reject(new Error()); `error1` here and below > + }); +}, 'writes should be satisfied in order when aborting'); + +promise_test(t => { + const ws = new WritableStream({ + write() { + return Promise.reject(new Error()); + } + }, new CountQueuingStrategy(4)); + const writer = ws.getWriter(); + return writer.ready.then(() => { + const resolveOrder = []; + return Promise.all([ + promise_rejects(t, new Error(), writer.write('1'), 'pending write should be rejected') + .then(() => resolveOrder.push(1)), + promise_rejects(t, new TypeError(), writer.write('2'), 'first queued write should be rejected') As before it makes more sense for me that the write() error sets the state, not abort(). -- You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub: https://github.com/whatwg/streams/pull/619#pullrequestreview-9778349
Received on Tuesday, 22 November 2016 23:25:57 UTC