簡體   English   中英

異步加載非關鍵資產(JavaScript,CSS)

[英]Async Loading of non-critical assets (Javascript, CSS)

為了更快地加載網站,我們需要先加載DOM,然后再獲取網站的非關鍵資產。 場景是:

1)優化CSS交付(在DOM加載后加載)

2)刪除阻止渲染的JavaScript(各種庫)並在以后加載。

3)我們可能有多個頁面,在這些頁面中有依賴於我們正在使用的庫的自定義代碼。

4)我們不需要使用requirejswebpack,因為我們唯一的要求是異步加載。

因此,我們需要一個簡單的javascript代碼,該代碼可以異步加載資產並在加載所有資產時觸發事件。 我們的使用庫函數的自定義代碼可以監聽該事件。

我們的布局或頁眉/頁腳可以包含此代碼,該代碼可加載指定的資源並在完成后觸發事件。

<body>
...
<script>
// Callback after window is loaded
if (window.addEventListener) {
  window.addEventListener("load", downloadFilesAtOnload, false);
} else if (window.attachEvent) {
  window.attachEvent("onload", downloadFilesAtOnload);
} else {
  window.onload = downloadFilesAtOnload;
}

function downloadFilesAtOnload() {
  // List of Javascript files to be loaded
  var jsFiles = ["js/library1.min.js", "js/library2.min.js", "CDN.library3.min.js"];
  loadScriptArray(jsFiles, function() {
    triggerEvent(document, 'scripts_loaded');
  });

  // List of CSS files to be loaded
  var robotoFonts = "https://fonts.googleapis.com/css?family=Roboto:400,300,300italic,400italic,500,500italic,700";
  var cssFiles = ["css/cssfile1.min.css", "css/cssfile2.min.css", robotoFonts];
  for (var i = 0; i < cssFiles.length; i++) {
    var l = document.createElement('link');
    l.rel = 'stylesheet';
    l.href = cssFiles[i];
    var h = document.getElementsByTagName('head')[0];
    h.parentNode.insertBefore(l, h);
  }
}

function loadScriptArray(contentArray, contentLoadedCallback){
  var contentQuantity = contentArray.length;      //Number of Files that needs to be loaded
  var contentCompleted = 0;                       //Number of Files, that have already been loaded
  for (var i = 0; i < contentQuantity; i++) {
    loadScript(contentArray[i], function(success, path){   //This anonymous function is called everytime a script is finished
      //The only way to know which script finished, is to pass the path as an parameter
      contentCompleted++;
      if (contentCompleted == contentQuantity){    //this was the last file
        if (typeof contentLoadedCallback == 'function'){
          contentLoadedCallback();
        }
      }
    });
  }
}

function loadScript(path, scriptLoadedCallback){
  element = document.createElement("script");
  element.src = path;
  element.async = false;
  if (typeof(scriptLoadedCallback) == 'function') {  //makes the callback-function optional
    element.onload = function() {
      return scriptLoadedCallback(true, path); //true = successfull; the path is needed later
    };
    element.onerror = function() {               //you might also call the cb on error
      this.parentNode.removeChild(this);       //remove faulty node from DOM
      return scriptLoadedCallback(false, path);      //false = error; the path is needed later
    };
  }
  document.body.appendChild(element);              //insert the node in DOM (end of <head>), and load the script
}

function processEvent(el, eventName, handler) {
  if (el.addEventListener) {
    el.addEventListener(eventName, handler);
  } else if (el.attachEvent) {
    el.attachEvent('on' + eventName, function() {
      handler.call(el);
    });
  }
}

function triggerEvent(el, eventName) {
  var event;
  if (window.CustomEvent) {
    event = new CustomEvent(eventName);
  } else {
    event = document.createEvent('CustomEvent');
    event.initCustomEvent(eventName);
  }
  el.dispatchEvent(event);
}
</script>
</body>

然后,我們可以使用依賴於此類任何頁面中的外部文件/庫的javascript代碼:

<script>
processEvent(document, 'scripts_loaded', function(e) {
    // Code here
});
</script>

這個答案的靈感來自https://stackoverflow.com/a/36063024/3113599

這是使用Javascript Promises的更好的解決方案

您的布局或頁眉/頁腳文件可以包含此代碼。

// Load css files
var cssFiles = [{
    type: "CDN",
    src: "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css",
    integrity: "sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u",
}, {
    type: "local",
    src: "css/cssfile1.min.css"
}, {
    type: "local",
    src: "css/cssfile2.min.css"
}, {
    type: "local",
    src: "https://fonts.googleapis.com/css?family=Roboto:400,300,300italic,400italic,500,500italic,700"
}];
var loadcssFiles = function() {
    cssFiles.forEach(function(file) {
        var style = document.createElement('link');
        style.rel = 'stylesheet';
        style.href = file.src;
        if (file.type == 'CDN') {
            style.integrity = file.integrity;
            style.crossOrigin = "anonymous";
        }
        document.head.appendChild(style);
    });
}
var raf = requestAnimationFrame || mozRequestAnimationFrame || webkitRequestAnimationFrame || msRequestAnimationFrame;
if (raf) {
    raf(loadcssFiles);
} else {
    window.addEventListener('load', loadcssFiles);
}

// Load Javascript files
var jsFiles = [{
    index: 1,
    type: "CDN",
    src: "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js",
    integrity: "sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa",
}, {
    index: 2,
    type: "local",
    src: "js/library1.min.js"
}, {
    index: 3,
    type: "local",
    src: "js/library2.min.js"
}];
var loadjsFiles = new Promise(function(resolve, reject) {
    var failed;
    jsFiles.forEach(function(file) {
        var script = document.createElement('script');
        script.src = file.src;
        script.onerror = function() {
            failed = true;
            reject(this);
        }
        script.async = false;
        if (file.type == 'CDN') {
            script.integrity = file.integrity;
            script.crossOrigin = "anonymous";
        }
        document.head.appendChild(script);
        script.onload = script.onreadystatechange = function() {
            if (!failed && (!this.readyState || this.readyState == "complete") && file.index == jsFiles.length ) {
                resolve(this);
            }
        }
    });
});

然后,我們可以使用依賴於此類任何頁面中的外部文件/庫的javascript代碼:

loadjsFiles.then(function() {
    // Code here
});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM