-
-
Notifications
You must be signed in to change notification settings - Fork 140
Description
Add memfs implementation of promises.watch and promises.watchFile.
Node.js documentation for context:
fsPromises.watch(filename[, options])#
filename<string> | <Buffer> | <URL>options<string> | <Object>persistent<boolean> Indicates whether the process should continue to run as long as files are being watched. Default:true.recursive<boolean> Indicates whether all subdirectories should be watched, or only the current directory. This applies when a directory is specified, and only on supported platforms (See caveats). Default:false.encoding<string> Specifies the character encoding to be used for the filename passed to the listener. Default:'utf8'.signal<AbortSignal> An <AbortSignal> used to signal when the watcher should stop.maxQueue<number> Specifies the number of events to queue between iterations of the <AsyncIterator> returned. Default:2048.overflow<string> Either'ignore'or'throw'when there are more events to be queued thanmaxQueueallows.'ignore'means overflow events are dropped and a warning is emitted, while'throw'means to throw an exception. Default:'ignore'.
- Returns: <AsyncIterator> of objects with the properties:
Returns an async iterator that watches for changes on filename, where filename is either a file or a directory.
const { watch } = require('node:fs/promises');const ac = new AbortController();
const { signal } = ac;
setTimeout(() => ac.abort(), 10000);
(async () => {copy
try {
const watcher = watch(__filename, { signal });
for await (const event of watcher)
console.log(event);
} catch (err) {
if (err.name === 'AbortError')
return;
throw err;
}
})();
On most platforms, 'rename' is emitted whenever a filename appears or disappears in the directory.
All the caveats for fs.watch() also apply to fsPromises.watch().
fsPromises.writeFile(file, data[, options])#
History
file<string> | <Buffer> | <URL> | <FileHandle> filename orFileHandledata<string> | <Buffer> | <TypedArray> | <DataView> | <AsyncIterable> | <Iterable> | <Stream>options<Object> | <string>encoding<string> | <null> Default:'utf8'mode<integer> Default:0o666flag<string> See support of file systemflags. Default:'w'.flush<boolean> If all data is successfully written to the file, andflushistrue,filehandle.sync()is used to flush the data. Default:false.signal<AbortSignal> allows aborting an in-progress writeFile
- Returns: <Promise> Fulfills with
undefinedupon success.
Asynchronously writes data to a file, replacing the file if it already exists. data can be a string, a buffer, an <AsyncIterable>, or an <Iterable> object.
The encoding option is ignored if data is a buffer.
If options is a string, then it specifies the encoding.
The mode option only affects the newly created file. See fs.open() for more details.
Any specified <FileHandle> has to support writing.
It is unsafe to use fsPromises.writeFile() multiple times on the same file without waiting for the promise to be settled.
Similarly to fsPromises.readFile - fsPromises.writeFile is a convenience method that performs multiple write calls internally to write the buffer passed to it. For performance sensitive code consider using fs.createWriteStream() or filehandle.createWriteStream().
It is possible to use an <AbortSignal> to cancel an fsPromises.writeFile(). Cancelation is "best effort", and some amount of data is likely still to be written.
import { writeFile } from 'node:fs/promises'; import { Buffer } from 'node:buffer';try {
const controller = new AbortController();
const { signal } = controller;
const data = new Uint8Array(Buffer.from('Hello Node.js'));
const promise = writeFile('message.txt', data, { signal });// Abort the request before the promise settles.
controller.abort();
await promise;copy
} catch (err) {
// When a request is aborted - err is an AbortError
console.error(err);
}
Aborting an ongoing request does not abort individual operating system requests but rather the internal buffering fs.writeFile performs.
Added in: v15.9.0, v14.18.0
filename | |
options |
persistent Indicates whether the process should continue to run as long as files are being watched. Default: true.
recursive Indicates whether all subdirectories should be watched, or only the current directory. This applies when a directory is specified, and only on supported platforms (See caveats). Default: false.
encoding Specifies the character encoding to be used for the filename passed to the listener. Default: 'utf8'.
signal An used to signal when the watcher should stop.
maxQueue Specifies the number of events to queue between iterations of the returned. Default: 2048.
overflow Either 'ignore' or 'throw' when there are more events to be queued than maxQueue allows. 'ignore' means overflow events are dropped and a warning is emitted, while 'throw' means to throw an exception. Default: 'ignore'.
Returns: of objects with the properties:
eventType The type of change
filename | | The name of the file changed.
Returns an async iterator that watches for changes on filename, where filename is either a file or a directory.
const { watch } = require('node:fs/promises');
const ac = new AbortController();
const { signal } = ac;
setTimeout(() => ac.abort(), 10000);
(async () => {
try {
const watcher = watch(__filename, { signal });
for await (const event of watcher)
console.log(event);
} catch (err) {
if (err.name === 'AbortError')
return;
throw err;
}
})(); copy
On most platforms, 'rename' is emitted whenever a filename appears or disappears in the directory.
All the caveats for fs.watch() also apply to fsPromises.watch().
fsPromises.writeFile(file, data[, options])#
History
file | | | filename or FileHandle
data | | | | | |
options |
encoding | Default: 'utf8'
mode Default: 0o666
flag See support of file system flags. Default: 'w'.
flush If all data is successfully written to the file, and flush is true, filehandle.sync() is used to flush the data. Default: false.
signal allows aborting an in-progress writeFile
Returns: Fulfills with undefined upon success.
Asynchronously writes data to a file, replacing the file if it already exists. data can be a string, a buffer, an , or an object.
The encoding option is ignored if data is a buffer.
If options is a string, then it specifies the encoding.
The mode option only affects the newly created file. See fs.open() for more details.
Any specified has to support writing.
It is unsafe to use fsPromises.writeFile() multiple times on the same file without waiting for the promise to be settled.
Similarly to fsPromises.readFile - fsPromises.writeFile is a convenience method that performs multiple write calls internally to write the buffer passed to it. For performance sensitive code consider using fs.createWriteStream() or filehandle.createWriteStream().
It is possible to use an to cancel an fsPromises.writeFile(). Cancelation is "best effort", and some amount of data is likely still to be written.
import { writeFile } from 'node:fs/promises';
import { Buffer } from 'node:buffer';
try {
const controller = new AbortController();
const { signal } = controller;
const data = new Uint8Array(Buffer.from('Hello Node.js'));
const promise = writeFile('message.txt', data, { signal });
// Abort the request before the promise settles.
controller.abort();
await promise;
} catch (err) {
// When a request is aborted - err is an AbortError
console.error(err);
} copy
Aborting an ongoing request does not abort individual operating system requests but rather the internal buffering fs.writeFile performs.
See Node.js watchers implementation for reference:
async function* watch(filename, options = kEmptyObject) {
const path = toNamespacedPath(getValidatedPath(filename));
validateObject(options, 'options');
const {
persistent = true,
recursive = false,
encoding = 'utf8',
maxQueue = 2048,
overflow = 'ignore',
signal,
} = options;
validateBoolean(persistent, 'options.persistent');
validateBoolean(recursive, 'options.recursive');
validateInteger(maxQueue, 'options.maxQueue');
validateOneOf(overflow, 'options.overflow', ['ignore', 'error']);
validateAbortSignal(signal, 'options.signal');
if (encoding && !isEncoding(encoding)) {
const reason = 'is invalid encoding';
throw new ERR_INVALID_ARG_VALUE('encoding', encoding, reason);
}
if (signal?.aborted)
throw new AbortError(undefined, { cause: signal.reason });
const handle = new FSEvent();
let { promise, resolve } = PromiseWithResolvers();
const queue = [];
const oncancel = () => {
handle.close();
resolve();
};
try {
if (signal) {
kResistStopPropagation ??= require('internal/event_target').kResistStopPropagation;
signal.addEventListener('abort', oncancel, { __proto__: null, once: true, [kResistStopPropagation]: true });
}
handle.onchange = (status, eventType, filename) => {
if (status < 0) {
const error = new UVException({
errno: status,
syscall: 'watch',
path: filename,
});
error.filename = filename;
handle.close();
ArrayPrototypePush(queue, error);
resolve();
return;
}
if (queue.length < maxQueue) {
ArrayPrototypePush(queue, { __proto__: null, eventType, filename });
resolve();
} else if (overflow === 'error') {
queue.length = 0;
ArrayPrototypePush(queue, new ERR_FS_WATCH_QUEUE_OVERFLOW(maxQueue));
resolve();
} else {
process.emitWarning('fs.watch maxQueue exceeded');
}
};
const err = handle.start(path, persistent, recursive, encoding);
if (err) {
const error = new UVException({
errno: err,
syscall: 'watch',
path: filename,
message: err === UV_ENOSPC ?
'System limit for number of file watchers reached' : '',
});
error.filename = filename;
handle.close();
throw error;
}
while (!signal?.aborted) {
await promise;
while (queue.length) {
const item = ArrayPrototypeShift(queue);
if (item instanceof Error) {
throw item;
} else {
yield item;
}
}
({ promise, resolve } = PromiseWithResolvers());
}
if (signal?.aborted) {
throw new AbortError(undefined, { cause: signal?.reason });
}
} finally {
handle.close();
signal?.removeEventListener('abort', oncancel);
}
}