写一个函数支持动态加载 JS & CSS

要求:

  1. 加载完成后可以执行方法
  2. 不能重复加载
  3. 支持 CSS 文件和 JS 文件加载

思路:

  1. 使用闭包解决重复加载问题
  2. 使用 Promise 解决执行成功后的回调问题

具体实现:

迷惑的地方:重复 import 导入函数,闭包还是否有效?实际上重复引入某个函数的时候,该方法是最开始函数执行后的 function,因此闭包会一直存在,多个文件内引入也会保留同一个闭包。

function load() {
  // 重复引入只会执行一次,因此闭包有效
  const loaded = new Map()

  return function (url: string) {

    if (loaded.has(url)) return Promise.resolve(true)

    return new Promise((resolve, reject) => {
      if (url.includes('css')) {
        const style = document.createElement('link')
        style.href = url
        style.rel = 'stylesheet'
        style.type = 'text/css'

        style.onload = () => {
          resolve(true)
        }

        style.onerror = (e) => {
          reject(e)
        }

        document.head.appendChild(style);
      } else if (url.includes('.js')) {
        loaded.set(url, true)
        const script = document.createElement('script');

        script.src = url

        script.onload = function () {
          resolve(true)
        }

        script.onerror = function (e) {
          reject(e)
        }

        document.body.appendChild(script);
      } else {
        throw new Error('url 类型不符合 css 或 js')
      }
    })
  }
}

export const loadAsset = load()