optimize performance

remove loops and function calls, modify arrays in place

this makes the whole thing harder to read, and probably only
marginally faster.
This commit is contained in:
Valentin Gagarin 2022-09-08 11:57:49 +02:00
parent 59be1e500a
commit 548c904d40

View file

@ -1,9 +1,12 @@
// Redirect rules for anchors ensure backwards compatibility of URLs.
// This must be done on the client side, as web servers do not see the anchor part of the URL.
// redirect rules for anchors ensure backwards compatibility of URLs.
// this must be done on the client side, as web servers do not see the anchor part of the URL.
// Redirections are declared as follows:
// Each entry has as key the matched URL path relative to the mdBook document root.
// Each entry is a set of key-value pairs, where
// redirections are declared as follows:
// each entry has as key the matched URL path relative to the mdBook document root.
//
// IMPORTANT: it must specify the full path with file name and suffix
//
// each entry is a set of key-value pairs, where
// - keys are anchors on to the matched path.
// - values are redirection targets relative to the current path.
@ -332,7 +335,7 @@ var redirects = {
"ssec-relnotes-2.2": "release-notes/rl-2.2.html",
"ssec-relnotes-2.3": "release-notes/rl-2.3.html"
},
"language/values": {
"language/values.html": {
"simple-values": "#primitives",
"lists": "#list",
"strings": "#string",
@ -341,73 +344,79 @@ var redirects = {
}
};
// the following code matches the current page's URL against the set of redirects.
//
// it is written to minimize the latency between page load and redirect.
// therefore we avoid function calls, copying data, and unnecessary loops.
// IMPORTANT: we use stateful array operations and their order matters!
//
// matching URLs is more involved than it should be:
//
// 1. `document.location.pathname` can have an have an arbitrary prefix.
//
// 2. `path_to_root` is set by mdBook and consists only of `../`s and
// determines the depth of `<path>` relative to the prefix:
//
// `document.location.pathname`
// |------------------------------|
// /<prefix>/<path>/[<file>[.html]][#<anchor>]
// |----|
// `path_to_root` has same number of segments
//
// source: https://phaiax.github.io/mdBook/format/theme/index-hbs.html#data
//
// 3. the following paths are equivalent:
//
// /foo/bar/
// /foo/bar/index.html
// /foo/bar/index
//
// 4. the following paths are also equivalent:
//
// /foo/bar/baz
// /foo/bar/baz.html
//
function pathsMatch(a, b, path_to_root) {
// Do paths `a` and `b` match?
//
// This is more involved than it should be:
//
// 1. Path `b` can have an have an arbitrary prefix.
//
// 2. `path_to_root` consists only of `../`s and determines the depth
// of `b` relative to the prefix:
//
// `document.location.pathname`
// |-----------------------------|
// <prefix>/<path>/[<file>[.html]][#<anchor>]
// |----|
// `path_to_root` has same number of segments
//
// 3. The following paths are equivalent:
//
// foo/bar/
// foo/bar/index.html
// foo/bar/index
//
// 4. The following paths are also equivalent:
//
// foo/bar/baz
// foo/bar/baz.html
//
// We can use `path_to_root` to discern prefix from path.
//
// The last element of the following split is always empty.
// Example: '../../'.split('/') -> [ '..', '..', '' ]
const depth = path_to_root.split('/').length - 1;
var segmentsB = b.split('/');
// get file name of `b`
const fileB = segmentsB.pop(); // mutates `segmentsB`!
// get path of `b` without prefix and file name
const pathB = segmentsB.slice(segmentsB.length - depth).join('/');
var segments = document.location.pathname.split('/');
var segmentsA = a.split('/');
const fileA = segmentsA.pop(); // mutates `segmentsA`!
const pathA = segmentsA.join('/')
var file = segments.pop();
function normalize(file) {
if (file === '') { return "index.html"; }
if (!file.endsWith('.html')) { return file + '.html'; }
return file;
}
// normalize file name
if (file === '') { file = "index.html"; }
else if (!file.endsWith('.html')) { file = file + '.html'; }
return pathA === pathB && normalize(fileA) === normalize(fileB);
}
segments.push(file);
// The anchor starts with the hash character (`#`),
// use `path_to_root` to discern prefix from path.
const depth = path_to_root.split('/').length;
// remove segments containing prefix. the following works because
// 1. the original `document.location.pathname` is absolute,
// hence first element of `segments` is always empty.
// 2. last element of splitting `path_to_root` is also always empty.
// 3. last element of `segments` is the file name.
//
// visual example:
//
// '/foo/bar/baz.html'.split('/') -> [ '', 'foo', 'bar', 'baz.html' ]
// '../'.split('/') -> [ '..', '' ]
//
// the following operations will then result in
//
// path = 'bar/baz.html'
//
segments.splice(0, segments.length - depth);
const path = segments.join('/');
// anchor starts with the hash character (`#`),
// but our redirect declarations don't, so we strip it.
// Example: document.location.hash -> '#foo'
// example: document.location.hash -> '#foo'
const anchor = document.location.hash.substring(1);
for (const [path, redirect] of Object.entries(redirects)) {
// The global variable `path_to_root` is set by `mdBook`:
//
// > This is a path containing exclusively `../`'s that points to the root of the
// > book from the current file. Since the original directory structure is
// > maintained, it is useful to prepend relative links with this `path_to_root`.
//
// Source: https://phaiax.github.io/mdBook/format/theme/index-hbs.html#data
if (pathsMatch(path, document.location.pathname, path_to_root) && redirect[anchor]) {
document.location.href = redirect[anchor];
break;
const redirect = redirects[path];
if (redirect) {
const target = redirect[anchor];
if (target) {
document.location.href = target;
}
}