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. // 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. // 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: // redirections are declared as follows:
// Each entry has as key the matched URL path relative to the mdBook document root. // 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 //
// 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. // - keys are anchors on to the matched path.
// - values are redirection targets relative to the current 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.2": "release-notes/rl-2.2.html",
"ssec-relnotes-2.3": "release-notes/rl-2.3.html" "ssec-relnotes-2.3": "release-notes/rl-2.3.html"
}, },
"language/values": { "language/values.html": {
"simple-values": "#primitives", "simple-values": "#primitives",
"lists": "#list", "lists": "#list",
"strings": "#string", "strings": "#string",
@ -341,73 +344,79 @@ var redirects = {
} }
}; };
// the following code matches the current page's URL against the set of redirects.
function pathsMatch(a, b, path_to_root) {
// Do paths `a` and `b` match?
// //
// This is more involved than it should be: // 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!
// //
// 1. Path `b` can have an have an arbitrary prefix. // matching URLs is more involved than it should be:
// //
// 2. `path_to_root` consists only of `../`s and determines the depth // 1. `document.location.pathname` can have an have an arbitrary prefix.
// of `b` relative to the 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` // `document.location.pathname`
// |-----------------------------| // |------------------------------|
// <prefix>/<path>/[<file>[.html]][#<anchor>] // /<prefix>/<path>/[<file>[.html]][#<anchor>]
// |----| // |----|
// `path_to_root` has same number of segments // `path_to_root` has same number of segments
// //
// 3. The following paths are equivalent: // source: https://phaiax.github.io/mdBook/format/theme/index-hbs.html#data
// //
// foo/bar/ // 3. the following paths are equivalent:
// foo/bar/index.html
// foo/bar/index
// //
// 4. The following paths are also equivalent: // /foo/bar/
// /foo/bar/index.html
// /foo/bar/index
// //
// foo/bar/baz // 4. the following paths are also equivalent:
// foo/bar/baz.html
// //
// We can use `path_to_root` to discern prefix from path. // /foo/bar/baz
// /foo/bar/baz.html
// //
// 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 segmentsA = a.split('/'); var segments = document.location.pathname.split('/');
const fileA = segmentsA.pop(); // mutates `segmentsA`!
const pathA = segmentsA.join('/')
function normalize(file) { var file = segments.pop();
if (file === '') { return "index.html"; }
if (!file.endsWith('.html')) { return file + '.html'; }
return file;
}
return pathA === pathB && normalize(fileA) === normalize(fileB); // normalize file name
} if (file === '') { file = "index.html"; }
else if (!file.endsWith('.html')) { file = file + '.html'; }
// The anchor starts with the hash character (`#`), segments.push(file);
// 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. // 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); const anchor = document.location.hash.substring(1);
for (const [path, redirect] of Object.entries(redirects)) { const redirect = redirects[path];
// The global variable `path_to_root` is set by `mdBook`: if (redirect) {
// const target = redirect[anchor];
// > This is a path containing exclusively `../`'s that points to the root of the if (target) {
// > book from the current file. Since the original directory structure is document.location.href = target;
// > 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;
} }
} }