Skip to content
This repository has been archived by the owner on Jul 15, 2019. It is now read-only.

Commit

Permalink
speed enhancement
Browse files Browse the repository at this point in the history
/* all -a implementations below are faster
findLastFile-a: 964ms
findLastFile-b: 2583ms
findQueryOrFragment-a: 523ms
findQueryOrFragment-b: 729ms
findFragment-a: 690ms
findFragment-b: 362ms
symbol-a: 58ms
symbol-b: 64ms
*/

var basePath = '/..#?';
var pos = -1;

console.time('findLastFile-a');
var re = /(?:[\/\\](?!(?:\.|%2[eE]){2})[^\/\\?#]*)?(?:$|[?#])/g;
for (var i = 0; i < 10000000; i++) {
	pos = re.exec(basePath).index;
}
console.timeEnd('findLastFile-a');

console.time('findLastFile-b');
var _resolvePathDoubleDots = /^(?:\.|%2[eE]){2}$/;
var pathEnd, t;
for (var i = 0; i < 10000000; i++) {
	var qPos = basePath.indexOf('?'), hashPos = basePath.indexOf('#');
	pos = (qPos === -1 || hashPos !== -1 && hashPos < qPos) ? hashPos :
qPos;
	pathEnd = pos === -1 ? undefined : pos;

	// _composeOriginSchemePath() normalized path to have at least the
first /
	t = Math.max(basePath.lastIndexOf('/', pathEnd),
			basePath.lastIndexOf('\\', pathEnd));

	// update pos as t only when the filename (after slash and until ?/#)
is not .. or equiv.
	!_resolvePathDoubleDots.test(basePath.slice(t + 1, pathEnd)) && (pos =
t);
}
console.timeEnd('findLastFile-b');

console.time('findQueryOrFragment-a');
var t, _reQueryOrFragment = /[?#]/;
for (var i = 0; i < 10000000; i++) {
	(t = _reQueryOrFragment.exec(basePath)) && (pos = t.index);
}
console.timeEnd('findQueryOrFragment-a');

console.time('findQueryOrFragment-b');
for (var i = 0; i < 10000000; i++) {
	var qPos = basePath.indexOf('?'), hashPos = basePath.indexOf('#');
	pos = (qPos === -1 || hashPos !== -1 && hashPos < qPos) ? hashPos :
qPos;
}
console.timeEnd('findQueryOrFragment-b');

console.time('findFragment-a');
var t, _reFragment = /#/;
for (var i = 0; i < 10000000; i++) {
	(t = _reFragment.exec(basePath)) && (pos = t.index);
}
console.timeEnd('findFragment-a');

console.time('findFragment-b');
for (var i = 0; i < 10000000; i++) {
	pos = basePath.indexOf('#');
}
console.timeEnd('findFragment-b');

var len = basePath.length;
console.time('symbol-a');
function symbolB (path, i) {
    switch(path.charCodeAt(i)) {
        case 47: case 92: return 1;
        case 35: case 63: return 2;
    }
    return 0;
}
for (var i = 0; i < 10000000; i++) {
	symbolB(basePath, i % len);
}
console.timeEnd('symbol-a');

console.time('symbol-b');
function symbolA (path, i) {
    var charCode = path.charCodeAt(i);
    return charCode === 47 || charCode === 92 ? 1 :
        charCode === 35 || charCode === 63 ? 2 :
        0;
}
for (var i = 0; i < 10000000; i++) {
	symbolA(basePath, i % len);
}
console.timeEnd('symbol-b');
  • Loading branch information
adon committed Nov 9, 2015
1 parent a9902b6 commit 878b878
Showing 1 changed file with 26 additions and 53 deletions.
79 changes: 26 additions & 53 deletions src/lib/urlResolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ function _absUrlResolver(url, origin, scheme, path, baseOrigin, baseScheme, base
return (scheme === '' ? baseScheme : '') + origin + path;
}

var _resolvePathDoubleDots = /^(?:\.|%2[eE]){2}$/, _resolvePathSingleDot = /^(?:\.|%2[eE])$/;
var _rePathDoubleDots = /^(?:\.|%2[eE]){2}$/,
_rePathSingleDot = /^(?:\.|%2[eE])$/,
_rePathQueryOrFragment = /[?#]/,
_rePathLastFile = /(?:[\/\\](?!(?:\.|%2[eE]){2})[^\/\\?#]*)?(?:$|[?#])/;

// return 1 for slash, 2 for ?/#, 0 otherwise
function _resolvePathSymbol(path, i) {
Expand All @@ -46,7 +49,7 @@ function _resolvePathSymbol(path, i) {
0;
}

// This resembles what is requried by the spec except things regarding file scheme
// This follows the spec except those specific for the file scheme
// Ref: https://url.spec.whatwg.org/#path-state
function _resolvePath(path, scheme) {
// _composeOriginSchemePath() normalized path to have at least the first /
Expand All @@ -56,18 +59,18 @@ function _resolvePath(path, scheme) {
if (j === len /* EOF */ || (symbol = _resolvePathSymbol(path, j))) {
buffer = path.slice(i, j);

if (_resolvePathDoubleDots.test(buffer)) {
if (_rePathDoubleDots.test(buffer)) {
arrPathLen !== 0 && --arrPathLen;
symbol !== 1 && (arrPath[arrPathLen++] = '');
} else if (_resolvePathSingleDot.test(buffer)) {
} else if (_rePathSingleDot.test(buffer)) {
symbol !== 1 && (arrPath[arrPathLen++] = '');
} else {
arrPath[arrPathLen++] = buffer;
}

// supposedly switch to query or fragment state, which is dont care here
if (symbol === 2) { break; }
// the index of character that is just after the last slash
// pos index of character that is just after the last slash
i = j + 1;
}
j++;
Expand All @@ -76,58 +79,28 @@ function _resolvePath(path, scheme) {
return slash + arrPath.slice(0, arrPathLen).join(slash) + path.slice(j);
}

// returns position of
// the first # if ? does not exists, or
// the first ? if # does not exists, or
// the first ? or #, whichever is earlier if both exist
// i.e., -1 means none of them exists
function _queryOrFragmentPosition(path) {
var qPos = path.indexOf('?'), hashPos = path.indexOf('#');
return (qPos === -1 || hashPos !== -1 && hashPos < qPos) ? hashPos : qPos;
}

function _relUrlResolver(path, baseOrigin, baseScheme, basePath, options) {
var resolve = options.resolvePath ? _resolvePath : function(p) {return p;};

if (path.length === 0) { return baseOrigin + resolve(basePath, baseScheme); }
var pos = -1, t, resolve = options.resolvePath ? _resolvePath : function(p) {return p;};

var pos = -1, pathEnd = -1, t, firstCharCode = path.charCodeAt(0);

/* / or \ */
if (firstCharCode === 47 || firstCharCode === 92) {
return baseOrigin + resolve(path, baseScheme);
if (path.length === 0) {
return baseOrigin + resolve(basePath, baseScheme);
}

/* # */
if (firstCharCode === 35) {
if (options.appendFragment) {
switch (path.charCodeAt(0)) {
case 47: case 92: /* / or \ */
return baseOrigin + resolve(path, baseScheme);
case 35: /* # */
if (!options.appendFragment) { return path; } // no _resolvePath needed
pos = basePath.indexOf('#');
} else { return path; } // no _resolvePath needed
}
/* ? or else */
else {
// the position of ? or #, whichever is earlier
pos = _queryOrFragmentPosition(basePath);

// advance to position of filename, meaning
// the last / or \\ before the position of ? or #
// but it must not be .. or its equiv. representations
if (firstCharCode !== 63) { // not ?

// remove the fromIndex constraint if no ? nor # was encountered
pathEnd = pos === -1 ? undefined : pos;

// _composeOriginSchemePath() normalized path to have at least the first /
t = Math.max(basePath.lastIndexOf('/', pathEnd),
basePath.lastIndexOf('\\', pathEnd));

// update pos as t only when the filename (after slash and until ?/#) is not .. or equiv.
!_resolvePathDoubleDots.test(basePath.slice(t + 1, pathEnd)) && (pos = t);

break;
case 63: /* ? */
(t = _rePathQueryOrFragment.exec(basePath)) && (pos = t.index);
break;
default:
(t = _rePathLastFile.exec(basePath)) && (pos = t.index);
path = '/' + path;
}
}

// replace base path's component, if any, with the new one
return baseOrigin + resolve(
(pos === -1 ? basePath : basePath.slice(0, pos)) + path, baseScheme);
Expand All @@ -140,7 +113,7 @@ function _unsafeUrlResolver(url) {
_urlFilters.yUrlResolver = function (options) {
options || (options = {});

var bFilter, rFilter,
var bFilter, urlFilter,
schemes = options.schemes,
relScheme = options.relScheme !== false,
absSchemeResolver = options.absResolver || {},
Expand All @@ -156,7 +129,7 @@ _urlFilters.yUrlResolver = function (options) {
schemes: schemes,
absCallback: function(url, scheme, auth, hostname, port, path) {
var _baseURL = _composeOriginSchemePath(scheme || '', auth, hostname, port, path);
rFilter = _urlFilters.yUrlFilterFactory({
urlFilter = _urlFilters.yUrlFilterFactory({
schemes: schemes,
relScheme: relScheme,
relPath: true,
Expand All @@ -179,6 +152,6 @@ _urlFilters.yUrlResolver = function (options) {
return function(url, baseURL) {
return (arguments.length >= 2 && !bFilter(baseURL) ?
unsafeResolver :
rFilter || unsafeResolver)(url);
urlFilter || unsafeResolver)(url);
};
};

0 comments on commit 878b878

Please sign in to comment.