关键渲染路径
关键路径渲染

避免阻塞型脚本
总的来说我们希望所有的资源能够尽可能快地加载完毕,不过往往为了保证首页加载的速度,我们会考虑将部分非首屏需要的
异步加载脚本
-
defer:如果
script 标签设置了该属性,则浏览器会异步的下载该文件并且不会影响到后续DOM 的渲染。如果有多个设置了defer 的script 标签存在,则会按照顺序执行所有的script 。defer 脚本会在文档渲染完毕后,DOMContentLoaded 事件调用前执行。 -
async:
async 浏览器立即异步下载文件,不同于defer 得是,下载完成会立即执行,此时会阻塞dom 渲染,所以async 的script 最好不要操作dom 。因为是下载完立即执行,不能保证多个加载时的先后顺序。

Lazy Load JS
目前来说,我们的网站都是偏向于静态,并不需要太多的defer
的属性,这保证了浏览器只会先将该脚本下载下来,然后等到整个页面加载完毕再执行该脚本。另一个需要注意的是,因为我们并不使用类似于
<script>
// Mustard Cutting
if ('querySelector' in document && 'addEventListener' in window) {
document.write('<script src="index.js" defer><\/script>');
}
</script>
Lazy Load CSS
正如上文所述,我们的网站偏向于静态展示,因此首屏的最大问题就是

上图中红色的线,即是所谓的折叠分割点。
Critical CSS
预加载
-
preload:让浏览器提前加载指定资源
( 加载后并不执行) ,需要执行时再执行 -
prefetch:它告诉浏览器,这段资源将会在未来某个导航或者功能要用到,但是本资源的下载顺序权重比较低。也就是说
prefetch 通常用于加速下一次导航,而不是本次的。被标记为prefetch 的资源,将会被浏览器在空闲时间加载。# 懒加载
代码分割

Loading Monitor( 加载监控)
PACE: 自动为页面添加加载指示

Installation
<head>
<script src="/pace/pace.js"></script>
<link href="/pace/themes/pace-theme-barber-shop.css" rel="stylesheet" />
</head>
LazyLoading( 懒加载)
JS-Loader
const promises = {};
function loadScript(src) {
if (promises[src]) {
return promises[src];
}
let promise = (promises[src] = new Promise((resolve) => {
var el = document.createElement("script");
var loaded = false;
el.onload = el.onreadystatechange = () => {
if (
(el.readyState &&
el.readyState !== "complete" &&
el.readyState !== "loaded") ||
loaded
) {
return false;
}
el.onload = el.onreadystatechange = null;
loaded = true;
resolve();
};
el.async = true;
el.src = src;
let head = document.getElementsByTagName("head")[0];
head.insertBefore(el, head.firstChild);
}));
return promise;
}
TinyLoader
loadCSS:A function for loading CSS asynchronously
/*! loadCSS: load a CSS file asynchronously. [c]2016 @scottjehl, Filament Group, Inc. Licensed MIT */
(function (w) {
"use strict";
/* exported loadCSS */
var loadCSS = function (href, before, media) {
// Arguments explained:
// `href` [REQUIRED] is the URL for your CSS file.
// `before` [OPTIONAL] is the element the script should use as a reference for injecting our stylesheet <link> before
// By default, loadCSS attempts to inject the link after the last stylesheet or script in the DOM. However, you might desire a more specific location in your document.
// `media` [OPTIONAL] is the media type or query of the stylesheet. By default it will be 'all'
var doc = w.document;
var ss = doc.createElement("link");
var ref;
if (before) {
ref = before;
} else {
var refs = (doc.body || doc.getElementsByTagName("head")[0]).childNodes;
ref = refs[refs.length - 1];
}
var sheets = doc.styleSheets;
ss.rel = "stylesheet";
ss.href = href;
// temporarily set media to something inapplicable to ensure it'll fetch without blocking render
ss.media = "only x";
// wait until body is defined before injecting link. This ensures a non-blocking load in IE11.
function ready(cb) {
if (doc.body) {
return cb();
}
setTimeout(function () {
ready(cb);
});
}
// Inject link
// Note: the ternary preserves the existing behavior of "before" argument, but we could choose to change the argument to "after" in a later release and standardize on ref.nextSibling for all refs
// Note: `insertBefore` is used instead of `appendChild`, for safety re: http://www.paulirish.com/2011/surefire-dom-element-insertion/
ready(function () {
ref.parentNode.insertBefore(ss, before ? ref : ref.nextSibling);
});
// A method (exposed on return object for external use) that mimics onload by polling until document.styleSheets until it includes the new sheet.
var onloadcssdefined = function (cb) {
var resolvedHref = ss.href;
var i = sheets.length;
while (i--) {
if (sheets[i].href === resolvedHref) {
return cb();
}
}
setTimeout(function () {
onloadcssdefined(cb);
});
};
function loadCB() {
if (ss.addEventListener) {
ss.removeEventListener("load", loadCB);
}
ss.media = media || "all";
}
// once loaded, set link's media back to `all` so that the stylesheet applies once it loads
if (ss.addEventListener) {
ss.addEventListener("load", loadCB);
}
ss.onloadcssdefined = onloadcssdefined;
onloadcssdefined(loadCB);
return ss;
};
// commonjs
if (typeof exports !== "undefined") {
exports.loadCSS = loadCSS;
} else {
w.loadCSS = loadCSS;
}
})(typeof global !== "undefined" ? global : this);
最基本的用法:
loadCSS( "path/to/mystylesheet.css" );
react-loadscript
npm install react react-loadscript --save
script-loading as a component
(I’m so sorry)
import {Script} from 'react-loadscript';
class App {
render(){
return <Script src='https://code.jquery.com/jquery-2.1.4.min.js'>{
({done}) => !done?
<div>loading...</div> :
<div>{$.map([1, 2, 3], i => <div>{i*5}</div>)}</div>
}</Script>
}
}
uses promises + a simple cache to prevent duplicate script loads. enjoy!
PreLoading( 预加载)
Link Prefetching( 预加载)
预加载网页内容为浏览者提供一个平滑的浏览体验。这个
<!-- full page -->
<link rel="prefetch" href="http://davidwalsh.name/css-enhancements-user-experience" />
<!-- just an image -->
<link rel="prefetch" href="http://davidwalsh.name/wp-content/themes/walshbook3/images/sprite.png" />
什么时候使用
- 当你做的是一种类似
slideshow 的网页,需要提前加载近1-3 张页面( 假设这些页面并不大) - 预先加载在网站中许多网页都会用到的图片
- 预先加载网站搜索的结果的页面
Browsers are beginning to support a standard markup pattern for loading CSS (and other file types) asynchronously: ``(W3C Spec). We recommend using this markup pattern to reference any CSS files that should be loaded asynchronously, and usingloadCSS
to polyfill support browsers that don’t yet support this new feature.
The markup for referencing your CSS file looks like this:
<link rel="preload" href="path/to/mystylesheet.css" as="style" onload="this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="path/to/mystylesheet.css"></noscript>
Since rel=preload
does not apply the CSS on its own (it merely fetches it), there is an onload
handler on the link
that will do that for us as soon as the CSS finishes loading. Since this step requires JavaScript, you may want to include an ordinary reference to your CSS file as well, using a noscript
element to ensure it only applies in non-JavaScript settings.
With that markup in the head
of your page, include the loadCSS script, as well as the loadCSS rel=preload polyfill script in your page (inline to run right away, or in an external file if the CSS is low-priority).
No further configuration is needed, as these scripts will automatically detect if the browsers supports rel=preload
, and if it does not, they will find CSS files referenced in the DOM and preload them using loadCSS. In browsers that natively support rel=preload
, these scripts will do nothing, allowing the browser to load and apply the asynchronous CSS (note the onload
attribute above, which is there to set the link
’s rel
attribute to stylesheet once it finishes loading in browsers that support rel=preload
).
Note: regardless of whether the browser supports rel=preload
or not, your CSS file will be referenced from the same spot in the source order as the original link
element. Keep this in mind, as you may want to place the link
in a particular location in your head
element so that the CSS loads with an expected cascade order.
You can view a demo of this rel=preload
pattern here: http://filamentgroup.github.io/loadCSS/test/preload.html
turbolinks
[pageAccelerator](
https://github.com/Easyfood/pageAccelerator)
Tags
External Link
script
script标签可以用于指示JavaScript源代码,也可以用于引入远端的js脚本文件。
野生动态加载脚本文件
function loadJs(sid, jsurl, callback) {
var nodeHead = document.getElementsByTagName("head")[0];
var nodeScript = null;
if (document.getElementById(sid) == null) {
nodeScript = document.createElement("script");
nodeScript.setAttribute("type", "text/javascript");
nodeScript.setAttribute("src", jsurl);
nodeScript.setAttribute("id", sid);
if (callback != null) {
nodeScript.onload = nodeScript.onreadystatechange = function () {
if (nodeScript.ready) {
return false;
}
if (
!nodeScript.readyState ||
nodeScript.readyState == "loaded" ||
nodeScript.readyState == "complete"
) {
nodeScript.ready = true;
callback();
}
};
}
nodeHead.appendChild(nodeScript);
} else {
if (callback != null) {
callback();
}
}
}
Github-LoadJs
// load a single file
loadjs("foo.js", function () {
// foo.js loaded
});
// load multiple files (in parallel)
loadjs(["foo.js", "bar.js"], function () {
// foo.js & bar.js loaded
});
// load multiple files (in series)
loadjs("foo.js", function () {
loadjs("bar.js", function () {
// foo.js loaded then bar.js loaded
});
});
// add a bundle id
loadjs(["foo.js", "bar.js"], "foobar", function () {
// foo.js & bar.js loaded
});
// add a failure callback
loadjs(
["foo.js", "bar.js"],
"foobar",
function () {
/* foo.js & bar.js loaded */
},
function (pathsNotFound) {
/* at least one path didn't load */
}
);
// execute a callback after bundle finishes loading
loadjs(["foo.js", "bar.js"], "foobar");
loadjs.ready("foobar", function () {
// foo.js & bar.js loaded
});
// .ready() can be chained together
loadjs("foo.js", "foo");
loadjs("bar.js", "bar");
loadjs
.ready("foo", function () {
// foo.js loaded
})
.ready("bar", function () {
// bar.js loaded
});
// compose more complex dependency lists
loadjs("foo.js", "foo");
loadjs("bar.js", "bar");
loadjs(["thunkor.js", "thunky.js"], "thunk");
// wait for multiple depdendencies
loadjs.ready(
["foo", "bar", "thunk"],
function () {
// foo.js & bar.js & thunkor.js & thunky.js loaded
},
function (depsNotFound) {
if (depsNotFound.indexOf("foo") > -1) {
} // foo failed
if (depsNotFound.indexOf("bar") > -1) {
} // bar failed
if (depsNotFound.indexOf("thunk") > -1) {
} // thunk failed
}
);
// use .done() for more control
loadjs.ready("my-awesome-plugin", function () {
myAwesomePlugin();
});
loadjs.ready("jquery", function () {
// plugin requires jquery
window.myAwesomePlugin = function () {
if (!window.jQuery) throw "jQuery is missing!";
};
// plugin is done loading
loadjs.done("my-awesome-plugin");
});