From 4a76c1280399ca6c8802063e6394b30a9af137a3 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Wed, 5 Jul 2017 21:06:38 +0200 Subject: [PATCH] Added mutation queues --- scripts/AnimeNotifier.ts | 23 ++++++++++++++++------- scripts/Diff.ts | 22 +++++++++++++++------- scripts/MutationQueue.ts | 29 +++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 14 deletions(-) create mode 100644 scripts/MutationQueue.ts diff --git a/scripts/AnimeNotifier.ts b/scripts/AnimeNotifier.ts index 32b374e5..fdaf4364 100644 --- a/scripts/AnimeNotifier.ts +++ b/scripts/AnimeNotifier.ts @@ -2,17 +2,26 @@ import { Application } from "./Application" import { Diff } from "./Diff" import { displayLocalDate } from "./DateView" import { findAll, delay } from "./Utils" +import { MutationQueue } from "./MutationQueue" import * as actions from "./Actions" export class AnimeNotifier { app: Application - visibilityObserver: IntersectionObserver user: HTMLElement + visibilityObserver: IntersectionObserver + + imageFound: MutationQueue + imageNotFound: MutationQueue + unmount: MutationQueue constructor(app: Application) { this.app = app this.user = null + this.imageFound = new MutationQueue(elem => elem.classList.add("image-found")) + this.imageNotFound = new MutationQueue(elem => elem.classList.add("image-not-found")) + this.unmount = new MutationQueue(elem => elem.classList.remove("mounted")) + if("IntersectionObserver" in window) { // Enable lazy load this.visibilityObserver = new IntersectionObserver( @@ -185,15 +194,15 @@ export class AnimeNotifier { img.src = img.dataset.src if(img.naturalWidth === 0) { - img.onload = function() { - this.classList.add("image-found") + img.onload = () => { + this.imageFound.queue(img) } - img.onerror = function() { - this.classList.add("image-not-found") + img.onerror = () => { + this.imageNotFound.queue(img) } } else { - img.classList.add("image-found") + this.imageFound.queue(img) } } @@ -210,7 +219,7 @@ export class AnimeNotifier { continue } - element.classList.remove("mounted") + this.unmount.queue(element) } } diff --git a/scripts/Diff.ts b/scripts/Diff.ts index 342e8186..2326bf50 100644 --- a/scripts/Diff.ts +++ b/scripts/Diff.ts @@ -1,4 +1,18 @@ export class Diff { + // Reuse container for diffs to avoid memory allocation + static container: HTMLElement + + // innerHTML will diff the element with the given HTML string and apply DOM mutations. + static innerHTML(aRoot: HTMLElement, html: string) { + if(!Diff.container) { + Diff.container = document.createElement("main") + } + + Diff.container.innerHTML = html + Diff.childNodes(aRoot, Diff.container) + } + + // childNodes diffs the child nodes of 2 given elements and applies DOM mutations. static childNodes(aRoot: Node, bRoot: Node) { let aChild = [...aRoot.childNodes] let bChild = [...bRoot.childNodes] @@ -33,6 +47,7 @@ export class Diff { let elemA = a as HTMLElement let elemB = b as HTMLElement + // Skip iframes if(elemA.tagName === "IFRAME") { continue } @@ -75,11 +90,4 @@ export class Diff { Diff.childNodes(a, b) } } - - static innerHTML(aRoot: HTMLElement, html: string) { - let bRoot = document.createElement("main") - bRoot.innerHTML = html - - Diff.childNodes(aRoot, bRoot) - } } \ No newline at end of file diff --git a/scripts/MutationQueue.ts b/scripts/MutationQueue.ts new file mode 100644 index 00000000..b353ab59 --- /dev/null +++ b/scripts/MutationQueue.ts @@ -0,0 +1,29 @@ +export class MutationQueue { + elements: Array + mutation: (elem: HTMLElement) => void + + constructor(mutation: (elem: HTMLElement) => void) { + this.mutation = mutation + this.elements = [] + } + + queue(elem: HTMLElement) { + this.elements.push(elem) + + if(this.elements.length === 1) { + window.requestAnimationFrame(() => this.mutateAll()) + } + } + + mutateAll() { + for(let i = 0; i < this.elements.length; i++) { + this.mutation(this.elements[i]) + } + + this.clear() + } + + clear() { + this.elements.length = 0 + } +} \ No newline at end of file