8000 Cache SourceMapConsumer Promise for performance · stacktracejs/stacktrace-gps@170bb4a · GitHub
[go: up one dir, main page]

Skip to content

Commit 170bb4a

Browse files
committed
Cache SourceMapConsumer Promise for performance
This allows us to avoid multiple SourceMapConsumers for the same source map URL. Issue: #41
1 parent 6fd0396 commit 170bb4a

File tree

2 files changed

+61
-23
lines changed

2 files changed

+61
-23
lines changed

spec/stacktrace-gps-spec.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,29 @@ describe('StackTraceGPS', function() {
4242
});
4343
});
4444

45+
describe('#_getSourceMapConsumer', function() {
46+
it('avoids duplicate SourceMapConsumers', function(done) {
47+
var sourceMap = '{"version":3,"sources":["./test.js"],"names":["foo","bar","baz","eval"],"mappings":"AAAA,GAAIA,KAAM,YACV,SAASC,QACT,GAAIC,KAAMC,KAAK","file":"test.min.js"}';
48+
var sourceMapUrl = 'http://localhost:9999/test.js.map';
49+
jasmine.Ajax.stubRequest(sourceMapUrl).andReturn({responseText: sourceMap});
50+
51+
var stackTraceGPS = new StackTraceGPS();
52+
stackTraceGPS._getSourceMapConsumer(sourceMapUrl).then(callback, done.fail);
53+
stackTraceGPS._getSourceMapConsumer(sourceMapUrl).then(callback, done.fail);
54+
55+
var callCount = 0;
56+
function callback() {
57+
callCount++;
58+
if (callCount === 1) {
59+
expect(stackTraceGPS.sourceMapConsumerCache[sourceMapUrl]).toBeTruthy();
60+
} else if (callCount === 2) {
61+
expect(Object.keys(stackTraceGPS.sourceMapConsumerCache).length).toBe(1);
62+
done();
63+
}
64+
}
65+
});
66+
});
67+
4568
describe('#findFunctionName', function() {
4669
it('rejects given non-object StackFrame', function(done) {
4770
StackTraceGPS().findFunctionName('').then(done.fail, done); // jshint ignore:line

stacktrace-gps.js

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@
134134
}
135135
}
136136

137-
138137
function _extractLocationInfoFromSourceMapSource(stackframe, sourceMapConsumer, sourceCache) {
139138
return new Promise(function(resolve, reject) {
140139
var loc = sourceMapConsumer.originalPositionFor({
@@ -143,11 +142,14 @@
143142
});
144143

145144
if (loc.source) {
145+
// cache mapped sources
146146
var mappedSource = sourceMapConsumer.sourceContentFor(loc.source);
147147
if (mappedSource) {
148148
sourceCache[loc.source] = mappedSource;
149149
}
150+
150151
resolve(
152+
// given stackframe and source location, update stackframe
151153
new StackFrame({
152154
functionName: loc.name || stackframe.functionName,
153155
args: stackframe.args,
@@ -216,6 +218,37 @@
216218
}.bind(this));
217219
};
218220

221+
/**
222+
* Creating SourceMapConsumers is expensive, so this wraps the creation of a
223+
* SourceMapConsumer in a per-instance cache.
224+
*
225+
* @param sourceMappingURL = {String} URL to fetch source map from
226+
* @param defaultSourceRoot = Default source root for source map if undefined
227+
* @returns {Promise} that resolves a SourceMapConsumer
228+
*/
229+
this._getSourceMapConsumer = function _getSourceMapConsumer(sourceMappingURL, defaultSourceRoot) {
230+
return new Promise(function(resolve, reject) {
231+
if (this.sourceMapConsumerCache[sourceMappingURL]) {
232+
resolve(this.sourceMapConsumerCache[sourceMappingURL]);
233+
} else {
234+
var sourceMapConsumerPromise = new Promise(function(resolve) {
235+
return this._get(sourceMappingURL).then(function(sourceMapSource) {
236+
if (typeof sourceMapSource === 'string') {
237+
sourceMapSource = _parseJson(sourceMapSource.replace(/^\)\]\}'/, ''));
238+
}
239+
if (typeof sourceMapSource.sourceRoot === 'undefined') {
240+
sourceMapSource.sourceRoot = defaultSourceRoot;
241+
}
242+
243+
resolve(new SourceMap.SourceMapConsumer(sourceMapSource));
244+
}, reject);
245+
}.bind(this));
246+
this.sourceMapConsumerCache[sourceMappingURL] = sourceMapConsumerPromise;
247+
resolve(sourceMapConsumerPromise);
248+
}
249+
}.bind(this));
250+
};
251+
219252
/**
220253
* Given a StackFrame, enhance function name and use source maps for a
221254
* better StackFrame.
@@ -278,40 +311,22 @@
278311
_ensureStackFrameIsLegit(stackframe);
279312

280313
var sourceCache = this.sourceCache;
281-
var sourceMapConsumerCache = this.sourceMapConsumerCache;
282314
var fileName = stackframe.fileName;
283315
this._get(fileName).then(function(source) {
284316
var sourceMappingURL = _findSourceMappingURL(source);
285317
var isDataUrl = sourceMappingURL.substr(0, 5) === 'data:';
286-
var base = fileName.substring(0, fileName.lastIndexOf('/') + 1);
318+
var defaultSourceRoot = fileName.substring(0, fileName.lastIndexOf('/') + 1);
287319

288320
if (sourceMappingURL[0] !== '/' && !isDataUrl && !(/^https?:\/\/|^\/\//i).test(sourceMappingURL)) {
289-
sourceMappingURL = base + sourceMappingURL;
290-
}
291-
292-
var cachedSourceMapConsumer = sourceMapConsumerCache[sourceMappingURL];
293-
if (cachedSourceMapConsumer !== undefined) {
294-
return _extractLocationInfoFromSourceMapSource(stackframe, cachedSourceMapConsumer, sourceCache)
295-
.then(resolve)['catch'](function() {
296-
resolve(stackframe);
297-
});
321+
sourceMappingURL = defaultSourceRoot + sourceMappingURL;
298322
}
299323

300-
return this._get(sourceMappingURL).then(function(sourceMapSource) {
301-
if (typeof sourceMapSource === 'string') {
302-
sourceMapSource = _parseJson(sourceMapSource.replace(/^\)\]\}'/, ''));
303-
}
304-
if (typeof sourceMapSource.sourceRoot === 'undefined') {
305-
sourceMapSource.sourceRoot = base;
306-
}
307-
308-
var sourceMapConsumer = new SourceMap.SourceMapConsumer(sourceMapSource);
309-
sourc 76BD eMapConsumerCache[sourceMappingURL] = sourceMapConsumer;
324+
return this._getSourceMapConsumer(sourceMappingURL, defaultSourceRoot).then(function(sourceMapConsumer) {
310325
return _extractLocationInfoFromSourceMapSource(stackframe, sourceMapConsumer, sourceCache)
311326
.then(resolve)['catch'](function() {
312327
resolve(stackframe);
313328
});
314-
}, reject)['catch'](reject);
329+
});
315330
}.bind(this), reject)['catch'](reject);
316331
}.bind(this));
317332
};

0 commit comments

Comments
 (0)
0