diff --git a/src/__tests__/process.test.ts b/src/__tests__/process.test.ts index 3752436ef..1e5aa2af4 100644 --- a/src/__tests__/process.test.ts +++ b/src/__tests__/process.test.ts @@ -9,10 +9,6 @@ describe('process', () => { it('.cwd()', () => { expect(typeof proc.cwd()).toBe('string'); }); - it('.nextTick()', done => { - expect(typeof proc.nextTick).toBe('function'); - proc.nextTick(done); - }); it('.env', () => { expect(typeof proc.env).toBe('object'); }); diff --git a/src/__tests__/queueMicrotask.ts b/src/__tests__/queueMicrotask.ts new file mode 100644 index 000000000..bbd428164 --- /dev/null +++ b/src/__tests__/queueMicrotask.ts @@ -0,0 +1,10 @@ +import queueMicrotask from '../queueMicrotask'; + +describe('queueMicrotask', () => { + it('Is a function', () => { + expect(typeof queueMicrotask).toBe('function'); + }); + it('Execute callback on next event loop cycle', done => { + queueMicrotask(done); + }); +}); diff --git a/src/__tests__/volume.test.ts b/src/__tests__/volume.test.ts index e482f9e9f..d1181ab26 100644 --- a/src/__tests__/volume.test.ts +++ b/src/__tests__/volume.test.ts @@ -6,6 +6,7 @@ import { Volume, filenameToSteps, StatWatcher } from '../volume'; import hasBigInt from './hasBigInt'; import { tryGetChild, tryGetChildNode } from './util'; import { genRndStr6 } from '../node/util'; +import queueMicrotask from '../queueMicrotask'; import { constants } from '../constants'; const { O_RDWR, O_SYMLINK } = constants; @@ -1361,7 +1362,7 @@ describe('volume', () => { vol.writeFileSync('/lol.txt', '1'); setTimeout(() => { vol.watchFile('/lol.txt', { interval: 1 }, (curr, prev) => { - process.nextTick(() => { + queueMicrotask(() => { vol.unwatchFile('/lol.txt'); done(); }); diff --git a/src/fsa-to-node/FsaNodeFs.ts b/src/fsa-to-node/FsaNodeFs.ts index 1ff691c8b..2cb97aea0 100644 --- a/src/fsa-to-node/FsaNodeFs.ts +++ b/src/fsa-to-node/FsaNodeFs.ts @@ -9,7 +9,7 @@ import { FsaNodeDirent } from './FsaNodeDirent'; import { AMODE } from '../consts/AMODE'; import { constants } from '../constants'; import { FsaNodeStats } from './FsaNodeStats'; -import process from '../process'; +import queueMicrotask from '../queueMicrotask'; import { FsSynchronousApi } from '../node/types/FsSynchronousApi'; import { FsaNodeWriteStream } from './FsaNodeWriteStream'; import { FsaNodeReadStream } from './FsaNodeReadStream'; @@ -84,7 +84,7 @@ export class FsaNodeFs extends FsaNodeCore implements FsCallbackApi, FsSynchrono util.validateCallback(callback); // This `if` branch is from Node.js if (length === 0) { - return process.nextTick(() => { + return queueMicrotask(() => { if (callback) callback(null, 0, buffer); }); } diff --git a/src/fsa-to-node/FsaNodeWriteStream.ts b/src/fsa-to-node/FsaNodeWriteStream.ts index 0c4ab98f4..7b45ee77b 100644 --- a/src/fsa-to-node/FsaNodeWriteStream.ts +++ b/src/fsa-to-node/FsaNodeWriteStream.ts @@ -4,6 +4,7 @@ import { concurrency } from 'thingies/es6/concurrency'; import { flagsToNumber } from '../node/util'; import { FLAG } from '../consts/FLAG'; import { FsaNodeFsOpenFile } from './FsaNodeFsOpenFile'; +import queueMicrotask from '../queueMicrotask'; import type { IFileSystemWritableFileStream } from '../fsa/types'; import type { IWriteStream } from '../node/types/misc'; import type { IWriteStreamOptions } from '../node/types/options'; @@ -86,7 +87,7 @@ export class FsaNodeWriteStream extends Writable implements IWriteStream { const emitClose = this.options.emitClose; await this.__mutex__(async () => { if (this.__closed__ && emitClose) { - process.nextTick(() => this.emit('close')); + queueMicrotask(() => this.emit('close')); return; } try { diff --git a/src/node/util.ts b/src/node/util.ts index 59c24d805..c97254bec 100644 --- a/src/node/util.ts +++ b/src/node/util.ts @@ -4,6 +4,7 @@ import type { FsCallbackApi } from './types'; import type * as misc from './types/misc'; import { ENCODING_UTF8, TEncodingExtended } from '../encoding'; import { bufferFrom } from '../internal/buffer'; +import queueMicrotask from '../queueMicrotask'; export const isWin = process.platform === 'win32'; @@ -44,7 +45,9 @@ export function nullCheck(path, callback?) { const er = new Error('Path must be a string without null bytes'); (er as any).code = 'ENOENT'; if (typeof callback !== 'function') throw er; - process.nextTick(callback, er); + queueMicrotask(() => { + callback(er); + }); return false; } return true; diff --git a/src/process.ts b/src/process.ts index 1cbdf24e6..f59559c81 100644 --- a/src/process.ts +++ b/src/process.ts @@ -8,7 +8,6 @@ export interface IProcess { cwd(): string; platform: string; - nextTick: (callback: (...args) => void, ...args) => void; emitWarning: (message: string, type: string) => void; env: {}; } @@ -39,7 +38,6 @@ export function createProcess(): IProcess { const p: IProcess = maybeReturnProcess() || ({} as IProcess); if (!p.cwd) p.cwd = () => '/'; - if (!p.nextTick) p.nextTick = require('./setImmediate').default; if (!p.emitWarning) p.emitWarning = (message, type) => { // tslint:disable-next-line:no-console diff --git a/src/queueMicrotask.ts b/src/queueMicrotask.ts new file mode 100644 index 000000000..5032dbe74 --- /dev/null +++ b/src/queueMicrotask.ts @@ -0,0 +1,4 @@ +export default typeof queueMicrotask === 'function' ? queueMicrotask : (cb => + Promise.resolve() + .then(() => cb()) + .catch(() => {})); diff --git a/src/volume.ts b/src/volume.ts index c9e1cc778..419b396f0 100644 --- a/src/volume.ts +++ b/src/volume.ts @@ -4,6 +4,7 @@ import Stats from './Stats'; import Dirent from './Dirent'; import { Buffer, bufferAllocUnsafe, bufferFrom } from './internal/buffer'; import setImmediate from './setImmediate'; +import queueMicrotask from './queueMicrotask'; import process from './process'; import setTimeoutUnref, { TSetTimeout } from './setTimeoutUnref'; import { Readable, Writable } from 'stream'; @@ -803,7 +804,7 @@ export class Volume implements FsCallbackApi, FsSynchronousApi { // This `if` branch is from Node.js if (length === 0) { - return process.nextTick(() => { + return queueMicrotask(() => { if (callback) callback(null, 0, buffer); }); } @@ -2059,7 +2060,9 @@ export class StatWatcher extends EventEmitter { stop() { clearTimeout(this.timeoutRef); - process.nextTick(emitStop, this); + queueMicrotask(() => { + emitStop.call(this, this); + }); } } @@ -2208,7 +2211,7 @@ FsReadStream.prototype.close = function (cb) { this.once('open', closeOnOpen); return; } - return process.nextTick(() => this.emit('close')); + return queueMicrotask(() => this.emit('close')); } // Since Node 18, there is only a getter for '.closed'. @@ -2374,7 +2377,7 @@ FsWriteStream.prototype.close = function (cb) { this.once('open', closeOnOpen); return; } - return process.nextTick(() => this.emit('close')); + return queueMicrotask(() => this.emit('close')); } // Since Node 18, there is only a getter for '.closed'.