Skip to content
This repository was archived by the owner on Aug 4, 2021. It is now read-only.

Commit e7eef7f

Browse files
keithamuslukastaegert
authored andcommitted
perf: add cached version of isDir (#218)
* perf: add cached version of `isDir` * refactor: DRY up cache functions * refactor: use Map for cache over Object * refactor: rename variables for clarity
1 parent 952033a commit e7eef7f

File tree

1 file changed

+27
-29
lines changed

1 file changed

+27
-29
lines changed

src/index.js

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,33 +9,29 @@ const ES6_BROWSER_EMPTY = resolve( __dirname, '../src/empty.js' );
99
// which deploy both ESM .mjs and CommonJS .js files as ESM.
1010
const DEFAULT_EXTS = [ '.mjs', '.js', '.json', '.node' ];
1111

12-
let readFileCache = {};
1312
const readFileAsync = file => new Promise((fulfil, reject) => fs.readFile(file, (err, contents) => err ? reject(err) : fulfil(contents)));
1413
const statAsync = file => new Promise((fulfil, reject) => fs.stat(file, (err, contents) => err ? reject(err) : fulfil(contents)));
15-
function cachedReadFile (file, cb) {
16-
if (file in readFileCache === false) {
17-
readFileCache[file] = readFileAsync(file).catch(err => {
18-
delete readFileCache[file];
19-
throw err;
20-
});
21-
}
22-
readFileCache[file].then(contents => cb(null, contents), cb);
23-
}
24-
25-
let isFileCache = {};
26-
function cachedIsFile (file, cb) {
27-
if (file in isFileCache === false) {
28-
isFileCache[file] = statAsync(file)
29-
.then(
30-
stat => stat.isFile(),
31-
err => {
32-
if (err.code === 'ENOENT') return false;
33-
delete isFileCache[file];
34-
throw err;
35-
});
36-
}
37-
isFileCache[file].then(contents => cb(null, contents), cb);
38-
}
14+
const cache = fn => {
15+
const cache = new Map();
16+
const wrapped = (param, done) => {
17+
if (cache.has(param) === false) {
18+
cache.set(param, fn(param).catch(err => {
19+
cache.delete(param);
20+
throw err;
21+
}));
22+
}
23+
return cache.get(param).then(result => done(null, result), done);
24+
};
25+
wrapped.clear = () => cache.clear();
26+
return wrapped;
27+
};
28+
const ignoreENOENT = err => {
29+
if (err.code === 'ENOENT') return false;
30+
throw err;
31+
};
32+
const readFileCached = cache(readFileAsync);
33+
const isDirCached = cache(file => statAsync(file).then(stat => stat.isDirectory(), ignoreENOENT));
34+
const isFileCached = cache(file => statAsync(file).then(stat => stat.isFile(), ignoreENOENT));
3935

4036
function getMainFields (options) {
4137
let mainFields;
@@ -99,8 +95,9 @@ export default function nodeResolve ( options = {} ) {
9995
},
10096

10197
generateBundle () {
102-
isFileCache = {};
103-
readFileCache = {};
98+
readFileCached.clear();
99+
isFileCached.clear();
100+
isDirCached.clear();
104101
},
105102

106103
resolveId ( importee, importer ) {
@@ -180,8 +177,9 @@ export default function nodeResolve ( options = {} ) {
180177
}
181178
return pkg;
182179
},
183-
readFile: cachedReadFile,
184-
isFile: cachedIsFile,
180+
readFile: readFileCached,
181+
isFile: isFileCached,
182+
isDirectory: isDirCached,
185183
extensions: extensions
186184
};
187185

0 commit comments

Comments
 (0)