前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >前端 实战项目·动态加载 JS 文件

前端 实战项目·动态加载 JS 文件

作者头像
数媒派
发布2022-12-01 11:37:44
5.2K0
发布2022-12-01 11:37:44
举报
文章被收录于专栏:产品优化

动态加载 JS 文件

对于 Vue、React 等框架开发的单页面应用,在某些页面开发特殊功能时经常需要依赖第三方 JS 文件,如果在全局引入 CDN 资源可能会加载冗余文件,此时最好使用动态加载方式。

动态加载 JS 脚本指仅在某些特殊页面引入依赖文件,而非全局引入,这样可以避免在这些页面并未打开时造成加载无用的资源,提高页面加载速度的同时,也让整个项目更加模块化。

文档对象模型(DOM)允许使用 JavaScript 动态创建 HTML。<script> 元素也是如此,它与页面其他元素没有什么不同,所以可以手动创建 <script> 来加载 JS 文件。

defer 与 async

<script> 元素有两个属性 deferasync 分别代表两种 JS 脚本的加载执行模式。

defer:此布尔属性被设置为向浏览器指示脚本在文档被解析后执行。 async:设置此布尔属性,以指示浏览器如果可能的话,应异步执行脚本。

对于 defer,可以认为是将外链的 js 放在了页面底部。js 的加载不会阻塞页面的渲染和资源的加载。defer 会按照原本的 js 的顺序执行。

对于 async,它的作用是能够异步的加载和执行脚本,同样不会阻塞页面的渲染和资源的加载,一旦加载到就会立刻执行。在有 async 的情况下,js 一旦下载好了就会执行,所以很有可能不是按照原本的顺序来执行的。如果多个脚本文件前后具有相互依赖性,用 async 就很有可能出错。

所以通俗来讲,浏览器首先会请求 HTML 文档,然后对其中的各种资源调用相应的资源加载器进行异步网络请求,同时进行 DOM 渲染,直到遇 <script> 到标签的时候,主进程才会停止渲染等待此资源加载完毕然后执行,继而继续进行 DOM 解析。如果加了 async 属性就相当于单独开了一个进程去独立加载和执行,而defer是和将 <script> 放到 <body> 底部一样的效果。

defer 与 async
defer 与 async

上图蓝色线代表网络读取,红色线代表执行时间,绿色线代表 HTML 解析。

代码语言:javascript
复制
const loadJS = (url, defer) => {
  const recaptchaScript = document.createElement('script')
  recaptchaScript.setAttribute('src', url)
  if (defer) {
    recaptchaScript.defer = true
  } else {
    recaptchaScript.async = true
  }
  recaptchaScript.onload = () => {
    console.log('加载完成', url)
  }
  document.head.appendChild(recaptchaScript)
}

下面举个栗子,这里加载五个 JS 脚本,其中 jquery-uifullcalendar 都依赖 jquery,而 locale 依赖 fullcalendar,这种情况需要让 JS 文件按照一定的依赖关系按次序加载资源。

代码语言:javascript
复制
const assets = [
  'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.0/jquery.min.js',
  'https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js',
  'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.9.0/moment.min.js',
  'https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.10.0/fullcalendar.min.js',
  'https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.10.0/locale/zh-cn.js'
]

assets.forEach(url => loadJS(url, true))

现实很骨感

然而在现实环境当中,浏览器对于延迟脚本并不一定会按照顺序执行,也不一定会在 DOMContentLoaded 事件触发前执行,因此仅使用 defer 来控制脚本文件的执行顺序有很大的风险,但可以通过监听 onload 事件来判断文件是否加载完成,配合 Promise 等待上一个脚本文件加载完成后再加载下一个文件,从而实现按次序加载执行脚本。

代码语言:javascript
复制
const loadJS = url => {
  return new Promise(resolve => {
    const recaptchaScript = document.createElement('script')
    recaptchaScript.setAttribute('src', url)
    recaptchaScript.defer = true
    recaptchaScript.onload = () => {
      resolve()
    }
    document.head.appendChild(recaptchaScript)
  }).catch(console.error)
}

// 按次序加载 JS 文件
const loadAssets = async () => {
  for (const url of assets) {
    await loadJS(url, true)
  }
}

Just enjoy it ฅ●ω●ฅ

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 动态加载 JS 文件
    • defer 与 async
      • 现实很骨感
      相关产品与服务
      内容分发网络 CDN
      内容分发网络(Content Delivery Network,CDN)通过将站点内容发布至遍布全球的海量加速节点,使其用户可就近获取所需内容,避免因网络拥堵、跨运营商、跨地域、跨境等因素带来的网络不稳定、访问延迟高等问题,有效提升下载速度、降低响应时间,提供流畅的用户体验。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档