Skip to content

Commit f2141e1

Browse files
authored
Merge pull request webpack#6365 from probablyup/timestamps-perf
perf: refactor various timestamp caches into ES6 Maps
2 parents 7de03f2 + 3adf072 commit f2141e1

10 files changed

+76
-45
lines changed

lib/CachePlugin.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class CachePlugin {
4242
compiler.hooks.run.tapAsync("CachePlugin", (compiler, callback) => {
4343
if(!compiler._lastCompilationFileDependencies) return callback();
4444
const fs = compiler.inputFileSystem;
45-
const fileTs = compiler.fileTimestamps = {};
45+
const fileTs = compiler.fileTimestamps = new Map();
4646
asyncLib.forEach(compiler._lastCompilationFileDependencies, (file, callback) => {
4747
fs.stat(file, (err, stat) => {
4848
if(err) {
@@ -53,14 +53,17 @@ class CachePlugin {
5353
if(stat.mtime)
5454
this.applyMtime(+stat.mtime);
5555

56-
fileTs[file] = +stat.mtime || Infinity;
56+
fileTs.set(file, +stat.mtime || Infinity);
57+
5758
callback();
5859
});
5960
}, err => {
6061
if(err) return callback(err);
61-
Object.keys(fileTs).forEach(key => {
62-
fileTs[key] += this.FS_ACCURENCY;
63-
});
62+
63+
for(const [file, ts] of fileTs) {
64+
fileTs.set(file, ts + this.FS_ACCURENCY);
65+
}
66+
6467
callback();
6568
});
6669
});

lib/Compiler.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ class Compiler extends Tapable {
7878
this.recordsOutputPath = null;
7979
this.records = {};
8080

81-
this.fileTimestamps = {};
82-
this.contextTimestamps = {};
81+
this.fileTimestamps = new Map();
82+
this.contextTimestamps = new Map();
8383

8484
this.resolverFactory = new ResolverFactory();
8585
this.resolvers = {
@@ -177,8 +177,8 @@ class Compiler extends Tapable {
177177
}
178178

179179
watch(watchOptions, handler) {
180-
this.fileTimestamps = {};
181-
this.contextTimestamps = {};
180+
this.fileTimestamps = new Map();
181+
this.contextTimestamps = new Map();
182182
return new Watching(this, watchOptions, handler);
183183
}
184184

lib/ContextModule.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ class ContextModule extends Module {
129129
}
130130

131131
needRebuild(fileTimestamps, contextTimestamps) {
132-
const ts = contextTimestamps[this.context];
132+
const ts = contextTimestamps.get(this.context);
133133
if(!ts) {
134134
return true;
135135
}

lib/NormalModule.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -543,12 +543,12 @@ class NormalModule extends Module {
543543
// Missing timestamp -> need rebuild
544544
// Timestamp bigger than buildTimestamp -> need rebuild
545545
for(const file of this.buildInfo.fileDependencies) {
546-
const timestamp = fileTimestamps[file];
546+
const timestamp = fileTimestamps.get(file);
547547
if(!timestamp) return true;
548548
if(timestamp >= this.buildTimestamp) return true;
549549
}
550550
for(const file of this.buildInfo.contextDependencies) {
551-
const timestamp = contextTimestamps[file];
551+
const timestamp = contextTimestamps.get(file);
552552
if(!timestamp) return true;
553553
if(timestamp >= this.buildTimestamp) return true;
554554
}

lib/WatchIgnorePlugin.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ class IgnoringWatchFileSystem {
4040
if(err) return callback(err);
4141

4242
ignoredFiles.forEach(path => {
43-
fileTimestamps[path] = 1;
43+
fileTimestamps.set(path, 1);
4444
});
4545

4646
ignoredDirs.forEach(path => {
47-
dirTimestamps[path] = 1;
47+
dirTimestamps.set(path, 1);
4848
});
4949

5050
callback(err, filesModified, dirsModified, missingModified, fileTimestamps, dirTimestamps);
@@ -56,14 +56,14 @@ class IgnoringWatchFileSystem {
5656
getContextTimestamps: () => {
5757
const dirTimestamps = watcher.getContextTimestamps();
5858
ignoredDirs.forEach(path => {
59-
dirTimestamps[path] = 1;
59+
dirTimestamps.set(path, 1);
6060
});
6161
return dirTimestamps;
6262
},
6363
getFileTimestamps: () => {
6464
const fileTimestamps = watcher.getFileTimestamps();
6565
ignoredFiles.forEach(path => {
66-
fileTimestamps[path] = 1;
66+
fileTimestamps.set(path, 1);
6767
});
6868
return fileTimestamps;
6969
}

lib/node/NodeWatchFileSystem.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"use strict";
66

77
const Watchpack = require("watchpack");
8+
const objectToMap = require("../util/objectToMap");
89

910
class NodeWatchFileSystem {
1011
constructor(inputFileSystem) {
@@ -41,7 +42,7 @@ class NodeWatchFileSystem {
4142
if(this.inputFileSystem && this.inputFileSystem.purge) {
4243
this.inputFileSystem.purge(changes);
4344
}
44-
const times = this.watcher.getTimes();
45+
const times = objectToMap(this.watcher.getTimes());
4546
callback(null,
4647
changes.filter(file => files.includes(file)).sort(),
4748
changes.filter(file => dirs.includes(file)).sort(),
@@ -67,15 +68,15 @@ class NodeWatchFileSystem {
6768
},
6869
getFileTimestamps: () => {
6970
if(this.watcher)
70-
return this.watcher.getTimes();
71+
return objectToMap(this.watcher.getTimes());
7172
else
72-
return {};
73+
return new Map();
7374
},
7475
getContextTimestamps: () => {
7576
if(this.watcher)
76-
return this.watcher.getTimes();
77+
return objectToMap(this.watcher.getTimes());
7778
else
78-
return {};
79+
return new Map();
7980
}
8081
};
8182
}

lib/util/objectToMap.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* convert an object into its 2D array equivalent to be turned
3+
* into an ES6 map
4+
*
5+
* @param {object} obj - any object type that works with Object.keys()
6+
* @returns {Map} an ES6 Map of KV pairs
7+
*/
8+
module.exports = function objectToMap(obj) {
9+
return new Map(Object.keys(obj).map(key => [key, obj[key]]));
10+
};

test/NodeWatchFileSystem.unittest.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ describe("NodeWatchFileSystem", function() {
6868
if(err) throw err;
6969
filesModified.should.be.eql([fileDirect]);
7070
dirsModified.should.be.eql([]);
71-
Object.assign({}, fileTimestamps).should.have.property(fileDirect).have.type("number");
71+
(typeof fileTimestamps.get(fileDirect)).should.be.eql("number");
7272
watcher.close();
7373
done();
7474
});
@@ -87,7 +87,7 @@ describe("NodeWatchFileSystem", function() {
8787
if(err) throw err;
8888
filesModified.should.be.eql([fileDirect]);
8989
dirsModified.should.be.eql([]);
90-
Object.assign({}, fileTimestamps).should.have.property(fileDirect).have.type("number");
90+
(typeof fileTimestamps.get(fileDirect)).should.be.eql("number");
9191
watcher.close();
9292
done();
9393
});
@@ -104,7 +104,7 @@ describe("NodeWatchFileSystem", function() {
104104
if(err) throw err;
105105
filesModified.should.be.eql([]);
106106
dirsModified.should.be.eql([fixtures]);
107-
Object.assign({}, dirTimestamps).should.have.property(fixtures).have.type("number");
107+
(typeof dirTimestamps.get(fixtures)).should.be.eql("number");
108108
watcher.close();
109109
done();
110110
});
@@ -123,7 +123,7 @@ describe("NodeWatchFileSystem", function() {
123123
if(err) throw err;
124124
filesModified.should.be.eql([]);
125125
dirsModified.should.be.eql([fixtures]);
126-
Object.assign({}, dirTimestamps).should.have.property(fixtures).have.type("number");
126+
(typeof dirTimestamps.get(fixtures)).should.be.eql("number");
127127
watcher.close();
128128
done();
129129
});
@@ -140,7 +140,7 @@ describe("NodeWatchFileSystem", function() {
140140
if(err) throw err;
141141
filesModified.should.be.eql([]);
142142
dirsModified.should.be.eql([fixtures]);
143-
Object.assign({}, dirTimestamps).should.have.property(fixtures).have.type("number");
143+
(typeof dirTimestamps.get(fixtures)).should.be.eql("number");
144144
watcher.close();
145145
done();
146146
});
@@ -159,7 +159,7 @@ describe("NodeWatchFileSystem", function() {
159159
if(err) throw err;
160160
filesModified.should.be.eql([]);
161161
dirsModified.should.be.eql([fixtures]);
162-
Object.assign({}, dirTimestamps).should.have.property(fixtures).have.type("number");
162+
(typeof dirTimestamps.get(fixtures)).should.be.eql("number");
163163
watcher.close();
164164
done();
165165
});
@@ -177,9 +177,9 @@ describe("NodeWatchFileSystem", function() {
177177
if(err) throw err;
178178
filesModified.should.be.eql([fileSubdir, fileDirect]);
179179
dirsModified.should.be.eql([fixtures]);
180-
Object.assign({}, fileTimestamps).should.have.property(fileDirect).have.type("number");
181-
Object.assign({}, fileTimestamps).should.have.property(fileSubdir).have.type("number");
182-
Object.assign({}, dirTimestamps).should.have.property(fixtures).have.type("number");
180+
(typeof fileTimestamps.get(fileDirect)).should.be.eql("number");
181+
(typeof fileTimestamps.get(fileSubdir)).should.be.eql("number");
182+
(typeof dirTimestamps.get(fixtures)).should.be.eql("number");
183183
watcher.close();
184184
done();
185185
});
@@ -197,9 +197,9 @@ describe("NodeWatchFileSystem", function() {
197197
if(err) throw err;
198198
filesModified.should.be.eql([fileSubdir, fileDirect]);
199199
dirsModified.should.be.eql([fixtures]);
200-
Object.assign({}, fileTimestamps).should.have.property(fileDirect).have.type("number");
201-
Object.assign({}, fileTimestamps).should.have.property(fileSubdir).have.type("number");
202-
Object.assign({}, dirTimestamps).should.have.property(fixtures).have.type("number");
200+
(typeof fileTimestamps.get(fileDirect)).should.be.eql("number");
201+
(typeof fileTimestamps.get(fileSubdir)).should.be.eql("number");
202+
(typeof dirTimestamps.get(fixtures)).should.be.eql("number");
203203
watcher.close();
204204
done();
205205
});

test/NormalModule.unittest.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -241,14 +241,14 @@ describe("NormalModule", function() {
241241
fileB = "fileB";
242242
fileDependencies = [fileA, fileB];
243243
contextDependencies = [fileA, fileB];
244-
fileTimestamps = {
245-
[fileA]: 1,
246-
[fileB]: 1,
247-
};
248-
contextTimestamps = {
249-
[fileA]: 1,
250-
[fileB]: 1,
251-
};
244+
fileTimestamps = new Map([
245+
[fileA, 1],
246+
[fileB, 1]
247+
]);
248+
contextTimestamps = new Map([
249+
[fileA, 1],
250+
[fileB, 1],
251+
]);
252252
normalModule.buildTimestamp = 2;
253253
setDeps(fileDependencies, contextDependencies);
254254
});
@@ -259,31 +259,31 @@ describe("NormalModule", function() {
259259
});
260260
describe("given a file timestamp is newer than the buildTimestamp", function() {
261261
beforeEach(function() {
262-
fileTimestamps[fileA] = 3;
262+
fileTimestamps.set(fileA, 3);
263263
});
264264
it("returns true", function() {
265265
normalModule.needRebuild(fileTimestamps, contextTimestamps).should.eql(true);
266266
});
267267
});
268268
describe("given a no file timestamp exists", function() {
269269
beforeEach(function() {
270-
fileTimestamps = {};
270+
fileTimestamps = new Map();
271271
});
272272
it("returns true", function() {
273273
normalModule.needRebuild(fileTimestamps, contextTimestamps).should.eql(true);
274274
});
275275
});
276276
describe("given a context timestamp is newer than the buildTimestamp", function() {
277277
beforeEach(function() {
278-
contextTimestamps[fileA] = 3;
278+
contextTimestamps.set(fileA, 3);
279279
});
280280
it("returns true", function() {
281281
normalModule.needRebuild(fileTimestamps, contextTimestamps).should.eql(true);
282282
});
283283
});
284284
describe("given a no context timestamp exists", function() {
285285
beforeEach(function() {
286-
contextTimestamps = {};
286+
contextTimestamps = new Map();
287287
});
288288
it("returns true", function() {
289289
normalModule.needRebuild(fileTimestamps, contextTimestamps).should.eql(true);

test/objectToMap.unittest.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/* globals describe it */
2+
3+
require("should");
4+
5+
var objectToMap = require("../lib/util/objectToMap");
6+
7+
describe("objectToMap", function() {
8+
it("should convert a plain object into a Map successfully", function() {
9+
const map = objectToMap({
10+
foo: "bar",
11+
bar: "baz"
12+
});
13+
14+
map.get("foo").should.eql("bar");
15+
map.get("bar").should.eql("baz");
16+
});
17+
});

0 commit comments

Comments
 (0)