HTML中 JavaScript 的加载方式


前言

相信各位前端的小伙伴都用过script元素,今天我们就来好好聊一聊它。


script元素

将JavaScript插入HTML的主要方法是使用〈〉元素,有下列8个属性

属性名 状态 描述
async 可选 表示应该立即下载脚本,但不能阻止其他页面动作,只对外部脚本文件有效
charset 可选 使用src属性指定的代码字符集(很少用,大部分浏览器不在乎)
crossorigin 可选 配置相关请求的cors设置,默认不用
defer 可选 表示在文档解析和显示完成后再执行脚本,只对外部脚本文件有效
integrityr 可选 允许比对接收道德资源和指定的加密签名以验证子资源的完整性,若接收子资源的加密签名与属性指定签名不匹配,则页面报错
language 废弃 最初用于表示代码块中的脚本语言
src 可选 表示要执行的代码的外部文件
type 可选 表示代码块中脚本语言的内容属性

src的优先级高于行内代码:使用了src属性的script元素,如果再在标签内包含其它javascript代码,会忽略行内代码。

<script src="xxx">
// 代码无效
function fn() {}
</script>

script 标签位置

head 标签内

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script>// ···js代码···</script>
</head>
<body>
</body>
</html>

但是这样意味着必须把所有 javascript 代码都下载、解析和解释完成后,才能开始渲染页面。当 javascript 代码很多的时候,会导致明显的渲染延迟

body 标签中页面内容后面

因为放在 head 标签内有如上渲染延迟问题,所以可以放在 body 标签中页面内容后面,如下所示:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><div><!-- 页面元素 --></div><script>// ···js代码···</script>
</body>
</html>

但是这样也会有问题无法复用逻辑,例如:我在 A 页面用到了加法逻辑,在 B 页面用到了相同的逻辑,但是由于 javascript 代码写在每个页面的 html 文件内,所以我不得不在两个页面写两段重复的代码,当这样的代码越来越多时,就会影响加载 javascript 代码的效率,

引入外部 javascript 代码

将 javascript 代码单独写在 js 文件内,哪个页面使用就引入该文件。

src工作原理

<script src="http://www.somewhere.com/file/js"></script>

当浏览器在解析这个资源的时候,会向 src 属性指定的路径发送一个 get 请求,以取得相应的资源,src 不受同源策略限制,jsonp 跨域就利用这个特性。

引入外部 javascript 代码的方式

推迟执行脚本

defer属性。这个属性表示会立即下载 src引入的资源文件(不会阻断解析HTML),当页面解析完毕后,再执行脚本。当同时有多个script元素使用了该属性,会按照它们出现的顺序执行

<!DOCTYPE html>
<html lang="en">
<head><script src="test1.js"></script><script src="test2.js"></script><title>Document</title>
</head>
<body>
</body>
</html>

例如上面的结构,在页面加载完成后执行外部资源文件时会先执行test1.js再执行test2.js.

异步执行脚本

async属性:这个属性表示会立即下载 src引入的资源文件,下载完成后立即执行,可能会阻断HTML解析,与defer不同的是当同时有多个script元素使用了该属性,不能保证会按照它们出现的顺序执行。因此,使用该属性重点在于引入的资源文件之间没有依赖关系。

<!DOCTYPE html>
<html lang="en">
<head><script src="test1.js"></script><script src="test2.js"></script><title>Document</title>
</head>
<body>
</body>
</html>

例如上面的结构,在页面加载完成后执行外部资源文件时也许会先执行test2.js再执行test1.js.

动态加载脚本

// 创建script
let script = document.createElement('script');
// 设置src属性
script.src = 'gibberish.js';
// 插入到head标签中
document.head.appendChild(script);

在将script插入到DOM且执行到这段代码之前不会发送请求下载src引入的资源。以这种方式创建的script是异步加载的,相当于添加了async属性。
问题:不是所有浏览器都支持async属性

可将其设置为同步加载

let script = document.createElement('script');
script.src = 'gibberish.js';
// 设置为同步加载
script.async = false;
document.head.appendChild(script);

问题:但是以这种方式获取资源对浏览器预加载器是不可见的,会严重影响它们在资源获取队列中的优先级,可能会严重影响性能。
解决办法:在文档头部显示的声明src引入的资源文件。

<link rel="preload" href="gibberish.js">

XHTML中的变化

在XHTML中使用 JavaScript 必须指定type属性且值为text/javascript,HTML中则可以没有这个属性。
在XHTML中语句a < b中的 < 会被解释成一个标签的开始,又因为作为标签开始的小于号后不能有空格,所以会导致语法错误。
有两种解决办法:

  1. 将代码中所有<换成对应HTML实体形式&lt;
  2. 将代码写在一个CDATA块中,CDATA快表示其内容不作为标签来解析。

在不支持CDATA块的非XHTML兼容浏览器中必须注释CDATA标记,下面这种格式适用于所有线代浏览器。

<script type="text/javascript">
//<![CDATA[function fn (a, b) {if (a < b) {return a - b;} else {return b - a;}}
//  ]]
</script>

开发最佳实践

虽然可以直接在HTML文件中嵌入JavaScript代码,但是通常认为最佳实践是尽可能将JavaScript代码放在外部文件。
外部文件的优势:

  1. 可维护性:一个目录中保存所有的JavaScript文件,比分散在HTML中更容易维护。
  2. 缓存:浏览器会根据特定的设置缓存所有的外部连接的JavaScript文件,当其他页面再用到该文件时不用下载,页面加载跟快。
  3. 适应未来:包含外部JavaScript文件的语法在HTML和XHTML中是一样的。

总结

script 标签中 defer 和 async 的区别

  • script :会阻碍 HTML 解析,只有下载好并执行完脚本才会继续解析 HTML。

  • async script :解析 HTML 过程中进行脚本的异步下载,下载成功立马执行,有可能会阻断 HTML 的解析。不一定按顺序执行脚本。

  • defer script:完全不会阻碍 HTML 的解析,解析完成之后再按照顺序执行脚本。

  • 动态加载脚本:相当于添加了async属性,但可能会影响属性。

为了提高项目的可维护性,在开发中尽量将javascript代码写在外部文件中再引入使用。
非常感谢这篇文章给予的帮助

  • script标签中的async、defer

我是孤城浪人,一名正在前端路上摸爬滚打的菜鸟,欢迎你的关注。

HTML 中 JavaScript 的加载方式相关推荐

  1. android fragment加载布局的方式,Android中Fragment的加载方式与数据通信详解

    Android中Fragment的加载方式与数据通信详解 发布时间:2020-08-22 18:55:57 来源:脚本之家 阅读:155 作者:Joah 一.加载方式 1. 静态加载 1.1 加载步骤 ...

  2. 浏览器中Javascript的加载和执行

    在刚学习Javascript时曾对该问题在小组内做个一次StudyReport,发现其中的基础还是值得分析的. 从标题分析,可以加个Javascript的加载和执行分为两个阶段:加载.执行.而加载即浏 ...

  3. 浅谈Entity Framework中的数据加载方式

    如果你还没有接触过或者根本不了解什么是Entity Framework,那么请看这里http://www.entityframeworktutorial.net/EntityFramework-Arc ...

  4. composition java_阿里P7架构师通过源码浅析Java中的资源加载

    一. 前提 最近在做一个基础组件项目刚好需要用到JDK中的资源加载,这里说到的资源包括类文件和其他静态资源,刚好需要重新补充一下类加载器和资源加载的相关知识,整理成一篇文章. 二. 什么是类加载器 虚 ...

  5. IDEA中Tomcat重新加载的几种方式

    IDEA中Tomcat重新加载的几种方式 参考自IDEA官方帮助文档 1.Update resources 更新资源文件,当项目中的HTML, JSP, JavaScript, CSS and ima ...

  6. ios首次加载web_IOS_IOS中UIWebView的使用详解,一、初始化与三种加载方式 UI - phpStudy...

    IOS中UIWebView的使用详解 一.初始化与三种加载方式 UIWebView继承与UIView,因此,其初始化方法和一般的view一样,通过alloc和init进行初始化,其加载数据的方式有三种 ...

  7. python ctypes库中动态链接库加载方式

    最近看了<Gray hat python>一书,这才知道为什么python是黑客必学的编程语言.通过python的ctypes模块,可以直接调用动态链接库中的导出函数,而且甚至可以直接在p ...

  8. 中yeti不能加载_将 PQ 查询加载到 Excel 中进行分析的三种常用的方式

    点击上方蓝字 关注星标★不迷路 岁月本长,忙者自促 虽然大部分时候经过PQ清洗的数据都是加载到Excel工作表中,但是PQ中还有另外两种将数据返回Excel中进行分析的方法. 三种不同的数据加载方式: ...

  9. 不一样的图片加载方式

    在浏览网页的过程中,图片最容易吸引用户的注意力,它即能给用户直观感受,又能清晰地表达意图,所以在制作网页时,如何快速有效地加载图片资源显得尤为重要. 常见的图片加载方式 一般而言,最常见的图片加载方式 ...

最新文章

  1. php字符串处理函数相关操作
  2. 可怕!315 曝光 50 多款App“窃听”:这条黑色产业链,有人靠你的隐私年赚千万...
  3. Java基础学习(1)
  4. linux FreeImage安装编译
  5. (转)Silverlight数据校验之INotifyDataErrorInfo
  6. [解析]多线程加锁Lock调用python2
  7. 励志!送女儿去厦大读研后,爸爸回家就考了厦大的博士,现在是女儿的“学弟”...
  8. java list有序还是无序_最详细的Java学习点知识脑图,从基础到进阶,看完还有啥你不懂的...
  9. 最让人纠结的等式:0.999...=1
  10. 通过Java反射来理解泛型的本质
  11. 海量网络存储系统原理与设计(三)
  12. 1k字让你理解死锁是什么?
  13. git 安装_Windows系统Git安装教程(详解Git安装过程)
  14. mysql清除内存不足_MySQL内存不足怎么办
  15. OpenCV绘制半透明效果的代码
  16. Zedgraph 总结
  17. 在virtual box虚拟机上下载sniffer pro
  18. 如何将两个mp3文件合成一个?
  19. 物联网毕业设计 - 基于单片机的自动写字机器人
  20. 从本质如何理解机器学习

热门文章

  1. QT工程转成VS2019+QT5.12的工程方法。(.pro to .sln)
  2. webpack打包5之配置清除dist目录插件
  3. LVS的负载均衡算法
  4. kafka的php使用场景,使用 PHP 处理 Kafka 消息
  5. “手把手”教你C语言八大排序
  6. 文件上传(JavaScript实现)
  7. java金融投资收益计算_投资收益怎么算
  8. 深度学习的应用——检测糖尿病型视网膜症
  9. 1 of ORDER BY clause is not in SELECT list, references column 'xxx' which is not in SELECT list
  10. 用汉字命名数据库字段名