197 lines
4.4 KiB
JavaScript
197 lines
4.4 KiB
JavaScript
|
|
// cssExpr 用于判断资源是否是css
|
|||
|
|
// eslint-disable-next-line prefer-regex-literals
|
|||
|
|
const cssExpr = new RegExp("\\.css")
|
|||
|
|
const nHead = document.head || document.getElementsByTagName("head")[0]
|
|||
|
|
// `onload` 在WebKit < 535.23, Firefox < 9.0 不被支持
|
|||
|
|
const isOldWebKit = +navigator.userAgent.replace(/.*(?:AppleWebKit|AndroidWebKit)\/?(\d+).*/i, "$1") < 536
|
|||
|
|
|
|||
|
|
// 判断对应的node节点是否已经载入完成
|
|||
|
|
function isReady(node) {
|
|||
|
|
return node.readyState === "complete" || node.readyState === "loaded"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// loadCss 用于载入css资源
|
|||
|
|
function loadCss(url, setting, callback) {
|
|||
|
|
const node = document.createElement("link")
|
|||
|
|
|
|||
|
|
node.rel = "stylesheet"
|
|||
|
|
addOnload(node, callback, "css")
|
|||
|
|
node.async = true
|
|||
|
|
node.href = url
|
|||
|
|
|
|||
|
|
nHead.appendChild(node)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// loadJs 用于载入js资源
|
|||
|
|
function loadJs(url, setting, callback) {
|
|||
|
|
const node = document.createElement("script")
|
|||
|
|
|
|||
|
|
node.charset = "utf-8"
|
|||
|
|
addOnload(node, callback, "js")
|
|||
|
|
node.async = !setting.sync
|
|||
|
|
node.src = url
|
|||
|
|
|
|||
|
|
nHead.appendChild(node)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 在老的webkit中,因不支持load事件,这里用轮询sheet来保证
|
|||
|
|
function pollCss(node, callback) {
|
|||
|
|
let isLoaded
|
|||
|
|
|
|||
|
|
if (node.sheet) {
|
|||
|
|
isLoaded = true
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
setTimeout(function () {
|
|||
|
|
if (isLoaded) {
|
|||
|
|
// 在这里callback 是为了让样式有足够的时间渲染
|
|||
|
|
callback()
|
|||
|
|
} else {
|
|||
|
|
pollCss(node, callback)
|
|||
|
|
}
|
|||
|
|
}, 20)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 用于给指定的节点绑定onload回调
|
|||
|
|
// 监听元素载入完成事件
|
|||
|
|
function addOnload(node, callback, type) {
|
|||
|
|
const supportOnload = "onload" in node
|
|||
|
|
const isCSS = type === "css"
|
|||
|
|
|
|||
|
|
// 对老的webkit和老的firefox的兼容
|
|||
|
|
if (isCSS && (isOldWebKit || !supportOnload)) {
|
|||
|
|
setTimeout(function () {
|
|||
|
|
pollCss(node, callback)
|
|||
|
|
}, 1)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (supportOnload) {
|
|||
|
|
node.onload = onload
|
|||
|
|
node.onerror = function (e) {
|
|||
|
|
node.onerror = null
|
|||
|
|
if (type === "css") {
|
|||
|
|
console.error("该css文件不存在:" + node.href, e)
|
|||
|
|
} else {
|
|||
|
|
console.error("该js文件不存在:" + node.src, e)
|
|||
|
|
}
|
|||
|
|
onload()
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
node.onreadystatechange = function () {
|
|||
|
|
if (isReady(node)) {
|
|||
|
|
onload()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function onload() {
|
|||
|
|
// 执行一次后清除,防止重复执行
|
|||
|
|
node.onload = node.onreadystatechange = null
|
|||
|
|
|
|||
|
|
node = null
|
|||
|
|
|
|||
|
|
callback()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 资源下载入口,根绝文件类型的不同,调用loadCss或者loadJs
|
|||
|
|
function loadItem(url, list, setting, callback) {
|
|||
|
|
// 如果加载的url为空,就直接成功返回
|
|||
|
|
if (!url) {
|
|||
|
|
setTimeout(function () {
|
|||
|
|
onFinishLoading()
|
|||
|
|
})
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (cssExpr.test(url)) {
|
|||
|
|
loadCss(url, setting, onFinishLoading)
|
|||
|
|
} else {
|
|||
|
|
loadJs(url, setting, onFinishLoading)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 每次资源下载完成后,检验是否结束整个list下载过程
|
|||
|
|
// 若已经完成所有下载,执行回调函数
|
|||
|
|
function onFinishLoading() {
|
|||
|
|
const urlIndex = list.indexOf(url)
|
|||
|
|
if (urlIndex > -1) {
|
|||
|
|
list.splice(urlIndex, 1)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (list.length === 0) {
|
|||
|
|
callback()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function doInit(list, setting, callback) {
|
|||
|
|
const cb = function () {
|
|||
|
|
callback && callback()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
list = Array.prototype.slice.call(list || [])
|
|||
|
|
|
|||
|
|
if (list.length === 0) {
|
|||
|
|
cb()
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for (let i = 0, len = list.length; i < len; i++) {
|
|||
|
|
loadItem(list[i], list, setting, cb)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 判断当前页面是否加载完
|
|||
|
|
// 加载完,立刻执行下载
|
|||
|
|
// 未加载完,等待页面load事件以后再进行下载
|
|||
|
|
function ready(node, callback) {
|
|||
|
|
if (isReady(node)) {
|
|||
|
|
callback()
|
|||
|
|
} else {
|
|||
|
|
// 1500ms 以后,直接开始下载资源文件,不再等待load事件
|
|||
|
|
const timeLeft = 1500
|
|||
|
|
let isExecute = false
|
|||
|
|
window.addEventListener("load", function () {
|
|||
|
|
if (!isExecute) {
|
|||
|
|
callback()
|
|||
|
|
isExecute = true
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
setTimeout(function () {
|
|||
|
|
if (!isExecute) {
|
|||
|
|
callback()
|
|||
|
|
isExecute = true
|
|||
|
|
}
|
|||
|
|
}, timeLeft)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 暴露出去的Loader
|
|||
|
|
// 提供async, sync两个函数
|
|||
|
|
// async 用作异步下载执行用,不阻塞页面渲染
|
|||
|
|
// sync 用作异步下载,顺序执行,保证下载的js按照数组顺序执行
|
|||
|
|
const Loader = {
|
|||
|
|
async: function (list, callback) {
|
|||
|
|
ready(document, function () {
|
|||
|
|
doInit(list, {}, callback)
|
|||
|
|
})
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
sync: function (list, callback) {
|
|||
|
|
ready(document, function () {
|
|||
|
|
doInit(
|
|||
|
|
list,
|
|||
|
|
{
|
|||
|
|
sync: true
|
|||
|
|
},
|
|||
|
|
callback
|
|||
|
|
)
|
|||
|
|
})
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
window.Loader = Loader;
|
|||
|
|
|