background

In daily front-end development, there are definitely requirements scenarios like this: A function that is rarely used introduces a large third-party SDK, and the third-party SDK does not provide the corresponding NPM package, so it cannot be introduced on demand. Instead, it can only be introduced in the way of labels in index.html. As a result, more files need to be loaded when the project is started, resulting in a prolonged first screen rendering time. You could also use the async and defer properties to tell the browser to delay execution, but you would still waste some loading resources.

So you can use dynamic loading of resources, only when necessary to dynamically load the corresponding resource file.

implementation

Dynamically loading JS

Realization idea:

  1. usecreateElementCreating a DOM element
  2. Set up thetypewithsrc
  3. Add the DOM element to the body
  4. Listen for loading success and failure to execute the corresponding callback function
export function loadJs(srcUrl) {
  return new Promise((resolve, reject) = > {
    const script = document.createElement('script')
    script.type = 'text/javascript'
    script.src = srcUrl
    document.body.appendChild(script)
    script.onload = () = > {
      resolve()
    }
    script.onerror = (err) = > {
      reject(err)
    }
  })
}
Copy the code

When creating the element dynamically, you may encounter that it has already been created and added to the body, which is a waste of resources (DOM creation is a waste of resources), so determine whether the current file already exists at creation time

.// Check whether the current js has been loaded
const scriptNodes = [].slice.call(document.querySelectorAll('script')).map(item= > item.src)
if (scriptNodes.includes(srcUrl)) return resolve()
...
Copy the code

The complete code

/** * Dynamic load js file *@param {*} SrcUrl File address *@returns Promise* /
export function loadJs(srcUrl) {
  return new Promise((resolve, reject) = > {
    // Check whether the current js has been loaded
    const scriptNodes = [].slice.call(document.querySelectorAll('script')).map(item= > item.src)
    if (scriptNodes.includes(srcUrl)) return resolve()

    const script = document.createElement('script')
    script.type = 'text/javascript'
    script.src = srcUrl
    document.body.appendChild(script)
    script.onload = () = > {
      resolve()
    }
    script.onerror = (err) = > {
      reject(err)
    }
  })
}
Copy the code

Dynamically loading the CSS

/** * Dynamic load js file *@param {*} HrefUrl file address *@returns Promise* /
export function loadCss(hrefUrl) {
  return new Promise((resolve, reject) = > {
    // Check whether the current CSS has been loaded
    const linkNodes = [].slice.call(document.querySelectorAll('link')).map(item= > item.href)
    if (linkNodes.includes(hrefUrl)) return resolve()

    const link = document.createElement('link')
    link.type = 'text/css'
    link.rel = 'stylesheet'
    link.href = hrefUrl
    document.head.appendChild(link)
    link.onload = () = > {
      resolve()
    }
    link.onerror = (err) = > {
      reject(err)
    }
  })
}
Copy the code

Load multiple files dynamically

/** * Dynamically load multiple files *@param {*} JsList JS file address list *@param {*} CssList CSS file address list *@returns Promise* /
export function asyncLoad(jsList, cssList) {
  return new Promise((resolve, reject) = > {
    const jsPromiseList = []
    const cssPromiseList = []
    jsList.forEach(item= > {
      jsPromiseList.push(loadJs(item))
    })
    cssList.forEach(item= > {
      cssPromiseList.push(loadCss(item))
    })
    Promise.all([
      ...cssPromiseList,
      ...jsPromiseList
    ]).then(_= > resolve()).catch(reject)
  })
}
Copy the code

use

loadJs('js_url').then(res= >...). loadCss('css_url').then(res= >...). asyncLoad(['js_url'. ] ['css_url'. ] ).then(res= >...).Copy the code