mirror of
https://github.com/denoland/deno.git
synced 2025-01-08 23:28:18 -05:00
fix(extensions/web): aborting a FileReader should not affect later reads (#11381)
Currently, calling the `abort()` method on a `FileReader` object aborts any current read operation, but it also prevents any read operation started at some later point from starting. The File API instead specifies that calling `abort()` should reset the `FileReader`'s state and result, as well as removing any queued tasks from the current operation that haven't yet run.
This commit is contained in:
parent
56635d3b52
commit
5b771e7e83
2 changed files with 18 additions and 10 deletions
|
@ -52,8 +52,8 @@
|
||||||
[result] = null;
|
[result] = null;
|
||||||
/** @type {null | DOMException} */
|
/** @type {null | DOMException} */
|
||||||
[error] = null;
|
[error] = null;
|
||||||
|
/** @type {null | {aborted: boolean}} */
|
||||||
[aborted] = false;
|
[aborted] = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Blob} blob
|
* @param {Blob} blob
|
||||||
|
@ -74,6 +74,12 @@
|
||||||
// 4. Set fr’s error to null.
|
// 4. Set fr’s error to null.
|
||||||
this[error] = null;
|
this[error] = null;
|
||||||
|
|
||||||
|
// We set this[aborted] to a new object, and keep track of it in a
|
||||||
|
// separate variable, so if a new read operation starts while there are
|
||||||
|
// remaining tasks from a previous aborted operation, the new operation
|
||||||
|
// will run while the tasks from the previous one are still aborted.
|
||||||
|
const abortedState = this[aborted] = { aborted: false };
|
||||||
|
|
||||||
// 5. Let stream be the result of calling get stream on blob.
|
// 5. Let stream be the result of calling get stream on blob.
|
||||||
const stream /*: ReadableStream<ArrayBufferView>*/ = blob.stream();
|
const stream /*: ReadableStream<ArrayBufferView>*/ = blob.stream();
|
||||||
|
|
||||||
|
@ -92,17 +98,17 @@
|
||||||
|
|
||||||
// 10 in parallel while true
|
// 10 in parallel while true
|
||||||
(async () => {
|
(async () => {
|
||||||
while (!this[aborted]) {
|
while (!abortedState.aborted) {
|
||||||
// 1. Wait for chunkPromise to be fulfilled or rejected.
|
// 1. Wait for chunkPromise to be fulfilled or rejected.
|
||||||
try {
|
try {
|
||||||
const chunk = await chunkPromise;
|
const chunk = await chunkPromise;
|
||||||
if (this[aborted]) return;
|
if (abortedState.aborted) return;
|
||||||
|
|
||||||
// 2. If chunkPromise is fulfilled, and isFirstChunk is true, queue a task to fire a progress event called loadstart at fr.
|
// 2. If chunkPromise is fulfilled, and isFirstChunk is true, queue a task to fire a progress event called loadstart at fr.
|
||||||
if (isFirstChunk) {
|
if (isFirstChunk) {
|
||||||
// TODO(lucacasonato): this is wrong, should be HTML "queue a task"
|
// TODO(lucacasonato): this is wrong, should be HTML "queue a task"
|
||||||
queueMicrotask(() => {
|
queueMicrotask(() => {
|
||||||
if (this[aborted]) return;
|
if (abortedState.aborted) return;
|
||||||
// fire a progress event for loadstart
|
// fire a progress event for loadstart
|
||||||
const ev = new ProgressEvent("loadstart", {});
|
const ev = new ProgressEvent("loadstart", {});
|
||||||
this.dispatchEvent(ev);
|
this.dispatchEvent(ev);
|
||||||
|
@ -128,7 +134,7 @@
|
||||||
});
|
});
|
||||||
// TODO(lucacasonato): this is wrong, should be HTML "queue a task"
|
// TODO(lucacasonato): this is wrong, should be HTML "queue a task"
|
||||||
queueMicrotask(() => {
|
queueMicrotask(() => {
|
||||||
if (this[aborted]) return;
|
if (abortedState.aborted) return;
|
||||||
this.dispatchEvent(ev);
|
this.dispatchEvent(ev);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -138,7 +144,7 @@
|
||||||
else if (chunk.done === true) {
|
else if (chunk.done === true) {
|
||||||
// TODO(lucacasonato): this is wrong, should be HTML "queue a task"
|
// TODO(lucacasonato): this is wrong, should be HTML "queue a task"
|
||||||
queueMicrotask(() => {
|
queueMicrotask(() => {
|
||||||
if (this[aborted]) return;
|
if (abortedState.aborted) return;
|
||||||
// 1. Set fr’s state to "done".
|
// 1. Set fr’s state to "done".
|
||||||
this[state] = "done";
|
this[state] = "done";
|
||||||
// 2. Let result be the result of package data given bytes, type, blob’s type, and encodingName.
|
// 2. Let result be the result of package data given bytes, type, blob’s type, and encodingName.
|
||||||
|
@ -232,7 +238,7 @@
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// TODO(lucacasonato): this is wrong, should be HTML "queue a task"
|
// TODO(lucacasonato): this is wrong, should be HTML "queue a task"
|
||||||
queueMicrotask(() => {
|
queueMicrotask(() => {
|
||||||
if (this[aborted]) return;
|
if (abortedState.aborted) return;
|
||||||
|
|
||||||
// chunkPromise rejected
|
// chunkPromise rejected
|
||||||
this[state] = "done";
|
this[state] = "done";
|
||||||
|
@ -303,7 +309,9 @@
|
||||||
}
|
}
|
||||||
// If there are any tasks from the context object on the file reading task source in an affiliated task queue, then remove those tasks from that task queue.
|
// If there are any tasks from the context object on the file reading task source in an affiliated task queue, then remove those tasks from that task queue.
|
||||||
// Terminate the algorithm for the read method being processed.
|
// Terminate the algorithm for the read method being processed.
|
||||||
this[aborted] = true;
|
if (this[aborted] !== null) {
|
||||||
|
this[aborted].aborted = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Fire a progress event called abort at the context object.
|
// Fire a progress event called abort at the context object.
|
||||||
const ev = new ProgressEvent("abort", {});
|
const ev = new ProgressEvent("abort", {});
|
||||||
|
|
|
@ -2794,7 +2794,7 @@
|
||||||
"reading-data-section": {
|
"reading-data-section": {
|
||||||
"Determining-Encoding.any.html": true,
|
"Determining-Encoding.any.html": true,
|
||||||
"FileReader-event-handler-attributes.any.html": true,
|
"FileReader-event-handler-attributes.any.html": true,
|
||||||
"FileReader-multiple-reads.any.html": false,
|
"FileReader-multiple-reads.any.html": true,
|
||||||
"filereader_abort.any.html": true,
|
"filereader_abort.any.html": true,
|
||||||
"filereader_error.any.html": true,
|
"filereader_error.any.html": true,
|
||||||
"filereader_events.any.html": false,
|
"filereader_events.any.html": false,
|
||||||
|
|
Loading…
Reference in a new issue