Enhanced Faster Webpage Loading with Pjax

Preload subsequent pages, lazy load images and videos, and use Pjax for faster webpage loading with robust error handling and fallback navigation.

当前为 2025-01-02 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Enhanced Faster Webpage Loading with Pjax
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.9
  5. // @description Preload subsequent pages, lazy load images and videos, and use Pjax for faster webpage loading with robust error handling and fallback navigation.
  6. // @author Tae
  7. // @match *://*/*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. (function () {
  12. 'use strict';
  13.  
  14. // Lazy load images, videos, and multimedia
  15. document.addEventListener("DOMContentLoaded", () => {
  16. const lazyElements = Array.from(document.querySelectorAll("img.lazy, video.lazy, iframe.lazy"));
  17.  
  18. function loadLazyElement(el) {
  19. const dataSrc = el.dataset.src;
  20. if (!dataSrc) return;
  21.  
  22. el.src = dataSrc;
  23. if (el.tagName === "VIDEO") {
  24. el.load();
  25. }
  26. el.classList.remove("lazy");
  27. }
  28.  
  29. if ("IntersectionObserver" in window) {
  30. const observer = new IntersectionObserver((entries, observer) => {
  31. entries.forEach(entry => {
  32. if (entry.isIntersecting) {
  33. loadLazyElement(entry.target);
  34. observer.unobserve(entry.target);
  35. }
  36. });
  37. });
  38.  
  39. lazyElements.forEach(el => observer.observe(el));
  40. } else {
  41. const lazyLoadFallback = () => {
  42. lazyElements.forEach((el, index) => {
  43. if (
  44. el.getBoundingClientRect().top < window.innerHeight &&
  45. el.getBoundingClientRect().bottom > 0 &&
  46. getComputedStyle(el).display !== "none"
  47. ) {
  48. loadLazyElement(el);
  49. lazyElements.splice(index, 1); // Remove loaded element
  50. }
  51. });
  52. if (lazyElements.length === 0) {
  53. document.removeEventListener("scroll", lazyLoadFallback);
  54. window.removeEventListener("resize", lazyLoadFallback);
  55. window.removeEventListener("orientationchange", lazyLoadFallback);
  56. }
  57. };
  58. document.addEventListener("scroll", lazyLoadFallback);
  59. window.addEventListener("resize", lazyLoadFallback);
  60. window.addEventListener("orientationchange", lazyLoadFallback);
  61. }
  62. });
  63.  
  64. // Prefetch links
  65. document.addEventListener("mouseover", event => {
  66. const link = event.target.closest("a[href]");
  67. if (link && !link.target && !link.rel.includes("nofollow")) {
  68. const href = link.href;
  69. if (/^https?:\/\//.test(href) && !href.includes("#")) {
  70. const prefetch = document.createElement("link");
  71. prefetch.rel = "prefetch";
  72. prefetch.href = href;
  73. document.head.appendChild(prefetch);
  74. }
  75. }
  76. });
  77.  
  78. // Initialize Pjax
  79. function initializePjax() {
  80. if (typeof Pjax === "undefined") {
  81. const script = document.createElement("script");
  82. script.src = "https://cdnjs.cloudflare.com/ajax/libs/pjax/0.2.8/pjax.min.js";
  83. script.onload = () => setupPjax();
  84. document.head.appendChild(script);
  85. } else {
  86. setupPjax();
  87. }
  88. }
  89.  
  90. function setupPjax() {
  91. const pjax = new Pjax({
  92. elements: "a[href]:not([target]):not([data-pjax-disabled])", // Only internal links
  93. selectors: ["title", ".content"], // Elements to update
  94. cacheBust: true, // Force cache refresh
  95. });
  96.  
  97. document.addEventListener("pjax:send", () => console.log("Pjax: Request sent"));
  98. document.addEventListener("pjax:complete", () => {
  99. console.log("Pjax: Request complete");
  100. reinitializeLazyLoading();
  101. });
  102. document.addEventListener("pjax:error", event => {
  103. console.error("Pjax: Error occurred", event);
  104. // Fallback to normal navigation
  105. window.location.href = event.request.responseURL || event.target.href;
  106. });
  107. }
  108.  
  109. function reinitializeLazyLoading() {
  110. const newLazyElements = Array.from(document.querySelectorAll("img.lazy, video.lazy, iframe.lazy:not([src])"));
  111. if ("IntersectionObserver" in window) {
  112. const observer = new IntersectionObserver((entries, observer) => {
  113. entries.forEach(entry => {
  114. if (entry.isIntersecting) {
  115. const el = entry.target;
  116. el.src = el.dataset.src;
  117. if (el.tagName === "VIDEO") el.load();
  118. observer.unobserve(el);
  119. }
  120. });
  121. });
  122.  
  123. newLazyElements.forEach(el => observer.observe(el));
  124. }
  125. }
  126.  
  127. // Initialize the script
  128. initializePjax();
  129. })();