1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-22 15:06:54 -05:00

feat(core): support AbortSignal in readFile (#10943)

This commit is contained in:
Benjamin Gruenbaum 2021-06-22 18:45:26 +03:00 committed by GitHub
parent 9c0b41e24b
commit 20b0a5125a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 53 additions and 9 deletions

View file

@ -861,6 +861,15 @@ declare namespace Deno {
mode?: number; mode?: number;
} }
export interface ReadFileOptions {
/**
* An abort signal to allow cancellation of the file read operation.
* If the signal becomes aborted the readFile operation will be stopped
* and the promise returned will be rejected with an AbortError.
*/
signal?: AbortSignal;
}
/** /**
* *
* Check if a given resource id (`rid`) is a TTY. * Check if a given resource id (`rid`) is a TTY.
@ -1385,7 +1394,10 @@ declare namespace Deno {
* ``` * ```
* *
* Requires `allow-read` permission. */ * Requires `allow-read` permission. */
export function readTextFile(path: string | URL): Promise<string>; export function readTextFile(
path: string | URL,
options?: ReadFileOptions,
): Promise<string>;
/** Synchronously reads and returns the entire contents of a file as an array /** Synchronously reads and returns the entire contents of a file as an array
* of bytes. `TextDecoder` can be used to transform the bytes to string if * of bytes. `TextDecoder` can be used to transform the bytes to string if
@ -1411,7 +1423,10 @@ declare namespace Deno {
* ``` * ```
* *
* Requires `allow-read` permission. */ * Requires `allow-read` permission. */
export function readFile(path: string | URL): Promise<Uint8Array>; export function readFile(
path: string | URL,
options?: ReadFileOptions,
): Promise<Uint8Array>;
/** A FileInfo describes a file and is returned by `stat`, `lstat`, /** A FileInfo describes a file and is returned by `stat`, `lstat`,
* `statSync`, `lstatSync`. */ * `statSync`, `lstatSync`. */

View file

@ -95,3 +95,25 @@ unitTest(
assertEquals(resourcesBefore, Deno.resources()); assertEquals(resourcesBefore, Deno.resources());
}, },
); );
unitTest(
{ perms: { read: true } },
async function readFileWithAbortSignal(): Promise<void> {
const ac = new AbortController();
queueMicrotask(() => ac.abort());
await assertThrowsAsync(async () => {
await Deno.readFile("cli/tests/fixture.json", { signal: ac.signal });
});
},
);
unitTest(
{ perms: { read: true } },
async function readTextileWithAbortSignal(): Promise<void> {
const ac = new AbortController();
queueMicrotask(() => ac.abort());
await assertThrowsAsync(async () => {
await Deno.readTextFile("cli/tests/fixture.json", { signal: ac.signal });
});
},
);

View file

@ -110,9 +110,12 @@
const READ_PER_ITER = 32 * 1024; const READ_PER_ITER = 32 * 1024;
async function readAll(r) { async function readAll(r) {
return await readAllInner(r);
}
async function readAllInner(r, options) {
const buffers = []; const buffers = [];
const signal = options?.signal ?? null;
while (true) { while (!signal?.aborted) {
const buf = new Uint8Array(READ_PER_ITER); const buf = new Uint8Array(READ_PER_ITER);
const read = await r.read(buf); const read = await r.read(buf);
if (typeof read == "number") { if (typeof read == "number") {
@ -121,6 +124,9 @@
break; break;
} }
} }
if (signal?.aborted) {
throw new DOMException("The read operation was aborted.", "AbortError");
}
let totalLen = 0; let totalLen = 0;
for (const buf of buffers) { for (const buf of buffers) {
@ -177,6 +183,7 @@
write, write,
writeSync, writeSync,
readAll, readAll,
readAllInner,
readAllSync, readAllSync,
}; };
})(this); })(this);

View file

@ -4,7 +4,7 @@
((window) => { ((window) => {
const core = window.Deno.core; const core = window.Deno.core;
const { open, openSync } = window.__bootstrap.files; const { open, openSync } = window.__bootstrap.files;
const { readAll, readAllSync } = window.__bootstrap.io; const { readAllInner, readAllSync } = window.__bootstrap.io;
function readFileSync(path) { function readFileSync(path) {
const file = openSync(path); const file = openSync(path);
@ -16,10 +16,10 @@
} }
} }
async function readFile(path) { async function readFile(path, options) {
const file = await open(path); const file = await open(path);
try { try {
const contents = await readAll(file); const contents = await readAllInner(file, options);
return contents; return contents;
} finally { } finally {
file.close(); file.close();
@ -36,10 +36,10 @@
} }
} }
async function readTextFile(path) { async function readTextFile(path, options) {
const file = await open(path); const file = await open(path);
try { try {
const contents = await readAll(file); const contents = await readAllInner(file, options);
return core.decode(contents); return core.decode(contents);
} finally { } finally {
file.close(); file.close();