From 44369cb9161d71b20d6ec0a9f77cbe5d60a69061 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Fri, 10 Nov 2017 08:41:45 +0100 Subject: [PATCH] Slightly improved diff performance --- pages/animelist/animelist.scarlet | 1 - scripts/Actions/Diff.ts | 7 ++++-- scripts/AnimeNotifier.ts | 18 +++++++++------- scripts/Application.ts | 20 +++++++---------- scripts/Diff.ts | 36 ++++++++++++++++++++----------- 5 files changed, 47 insertions(+), 35 deletions(-) diff --git a/pages/animelist/animelist.scarlet b/pages/animelist/animelist.scarlet index c1466b2a..7a78a90b 100644 --- a/pages/animelist/animelist.scarlet +++ b/pages/animelist/animelist.scarlet @@ -1,5 +1,4 @@ .anime-list-container - vertical width 100% max-width 800px margin 0 auto diff --git a/scripts/Actions/Diff.ts b/scripts/Actions/Diff.ts index b3213edc..b141c7c4 100644 --- a/scripts/Actions/Diff.ts +++ b/scripts/Actions/Diff.ts @@ -9,8 +9,11 @@ export function load(arn: AnimeNotifier, element: HTMLElement) { // Diff export function diff(arn: AnimeNotifier, element: HTMLElement) { let url = element.dataset.url || (element as HTMLAnchorElement).getAttribute("href") - + arn.diff(url) - .then(() => arn.scrollTo(element)) + .then(() => { + // Avoid instant layout thrashing + arn.requestIdleCallback(() => arn.scrollTo(element)) + }) .catch(console.error) } \ No newline at end of file diff --git a/scripts/AnimeNotifier.ts b/scripts/AnimeNotifier.ts index 5acbd97b..5a219955 100644 --- a/scripts/AnimeNotifier.ts +++ b/scripts/AnimeNotifier.ts @@ -294,6 +294,10 @@ export class AnimeNotifier { } countUp() { + if(!this.app.currentPath.includes("/paypal/success")) { + return + } + for(let element of findAll("count-up")) { let final = parseInt(element.innerText) let duration = 2000.0 @@ -384,9 +388,7 @@ export class AnimeNotifier { return Promise.resolve(response) }) .then(response => response.text()) - .then(html => { - Diff.root(document.documentElement, html) - }) + .then(html => Diff.root(document.documentElement, html)) .then(() => this.app.emit("DOMContentLoaded")) .then(() => this.loading(false)) // Because our loading element gets reset due to full page diff } @@ -605,9 +607,7 @@ export class AnimeNotifier { let request = fetch(path, { credentials: "same-origin" }) - .then(response => { - return response.text() - }) + .then(response => response.text()) history.pushState(url, null, url) this.app.currentPath = url @@ -617,7 +617,7 @@ export class AnimeNotifier { // Delay by transition-speed return delay(200).then(() => request) - .then(html => this.app.setContent(html, true)) + .then(html => Diff.innerHTML(this.app.content, html)) .then(() => this.app.emit("DOMContentLoaded")) .then(() => this.loading(false)) .catch(console.error) @@ -664,9 +664,11 @@ export class AnimeNotifier { const contentPadding = 24 let scrollHandle: number - let oldScroll = this.app.content.parentElement.scrollTop let newScroll = 0 let finalScroll = Math.max(target.offsetTop - contentPadding, 0) + + // Calculating scrollTop will force a layout - careful! + let oldScroll = this.app.content.parentElement.scrollTop let scrollDistance = finalScroll - oldScroll if(scrollDistance > 0 && scrollDistance < 4) { diff --git a/scripts/Application.ts b/scripts/Application.ts index 2b8c395d..99f0af09 100644 --- a/scripts/Application.ts +++ b/scripts/Application.ts @@ -39,7 +39,7 @@ export class Application { this.lastRequest.abort() this.lastRequest = null } - + return new Promise((resolve, reject) => { let request = new XMLHttpRequest() @@ -71,7 +71,7 @@ export class Application { if(options.addToHistory === undefined) { options.addToHistory = true } - + // Set current path this.currentPath = url @@ -85,14 +85,14 @@ export class Application { if(e.target !== this.content) { return } - + // Remove listener after we finally got the correct event. this.content.removeEventListener("transitionend", onTransitionEnd) // Wait for the network request to end. request.then(html => { // Set content - this.setContent(html, false) + this.setContent(html) this.scrollToTop() // Fade animations @@ -113,19 +113,15 @@ export class Application { return request } - setContent(html: string, diff: boolean) { - if(diff) { - Diff.innerHTML(this.content, html) - } else { - this.content.innerHTML = html - } + setContent(html: string) { + this.content.innerHTML = html } markActiveLinks(element?: HTMLElement) { if(element === undefined) element = document.body - let links = element.querySelectorAll("a") + let links = element.getElementsByTagName("a") for(let i = 0; i < links.length; i++) { let link = links[i] @@ -165,7 +161,7 @@ export class Application { if(!url || url === self.currentPath) return - + // Load requested page self.load(url) } diff --git a/scripts/Diff.ts b/scripts/Diff.ts index de3bdcfc..8f0bd397 100644 --- a/scripts/Diff.ts +++ b/scripts/Diff.ts @@ -7,23 +7,35 @@ export class Diff { static rootContainer: HTMLElement // innerHTML will diff the element with the given HTML string and apply DOM mutations. - static innerHTML(aRoot: HTMLElement, html: string) { + static innerHTML(aRoot: HTMLElement, html: string): Promise { if(!Diff.container) { Diff.container = document.createElement("main") } - + Diff.container.innerHTML = html - Diff.childNodes(aRoot, Diff.container) + + return new Promise((resolve, reject) => { + window.requestAnimationFrame(() => { + Diff.childNodes(aRoot, Diff.container) + resolve() + }) + }) } // root will diff the document root element with the given HTML string and apply DOM mutations. static root(aRoot: HTMLElement, html: string) { - if(!Diff.rootContainer) { - Diff.rootContainer = document.createElement("html") - } - - Diff.rootContainer.innerHTML = html.replace("", "") - Diff.childNodes(aRoot.getElementsByTagName("body")[0], Diff.rootContainer.getElementsByTagName("body")[0]) + return new Promise((resolve, reject) => { + if(!Diff.rootContainer) { + Diff.rootContainer = document.createElement("html") + } + + Diff.rootContainer.innerHTML = html.replace("", "") + + window.requestAnimationFrame(() => { + Diff.childNodes(aRoot.getElementsByTagName("body")[0], Diff.rootContainer.getElementsByTagName("body")[0]) + resolve() + }) + }) } // childNodes diffs the child nodes of 2 given elements and applies DOM mutations. @@ -31,7 +43,7 @@ export class Diff { let aChild = [...aRoot.childNodes] let bChild = [...bRoot.childNodes] let numNodes = Math.max(aChild.length, bChild.length) - + for(let i = 0; i < numNodes; i++) { let a = aChild[i] @@ -69,7 +81,7 @@ export class Diff { let elemB = b as HTMLElement let removeAttributes: Attr[] = [] - + for(let x = 0; x < elemA.attributes.length; x++) { let attrib = elemA.attributes[x] @@ -119,7 +131,7 @@ export class Diff { continue } - + elemA.setAttribute(attrib.name, attrib.value) }