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;
 | 
						||
 |