2.1.3:异步执行脚本
HTML5为<脚本script>元素定义了async属性。从改变脚本处理方式来看,async属性与defer相似。当然,它们两者也都只适用于外部脚本,都会告诉浏览器立即开始下载。但async与defer不同的是async脚本不保证能按照它们出现的次数执行,例子如下:
<!DOCTYPE html>
<html>
<head>
<title>Example HTML Page</title>
<script async src="example1.js"></script>
<script async src="example2.js"></script>
</head>
<body>
<!-- 这里是页面内容 -->
</body>
</html>
这个例子当中,第二个脚本可能先于第一个脚本执行,两者没有依赖关系,给脚本添加async属性的目的知识告诉浏览器不必等脚本下载和执行完后再加载页面,同样也不必等到该异步脚本下载和执行后再加载其他脚本。正因如此,异步脚本不应该在加载期间修改DOM,异步脚本保证会在页面的load事件前执行。
2.1.4:动态加载脚本
除了<脚本script>标签,还有其他方式可加载脚本,因为JavaScript可以使用DOM API,所以通过DOM中动态添加script元素同样可以加载指定的脚本,只需要创建一个script元素并将其添加到DOM。
let script = document.createElement('script')
script.src = 'gibberish.js'
document.head.appendChild(script);
当然,在把HTMLElement元素添加到DOM且执行到这段代码之前不会发送请求。默认情况下,以这种方式创建的<脚本script>元素是以异步方式加载的,相当于添加了async属性。不过这样做可能会有问题,因为所有浏览器都支持createElement()方法,但不是所有的浏览器都支持async属性,因此如果要统一动态脚本的加载行为,可以明确将其设置为同步加载:
let script = document.createElement('script')
script.src = 'gibberish.js'
script.async = false
document.head.appendChild(script)
以这种方式获取的资源对浏览器加载时不可取,会影响它们在资源获取队列中的优先级,
根据应用程序的工作方式以及怎么使用,这种方式可能会影响性能。要想让预加载知道这些动态请求文件的存在,可以在文档头部显示声明它们:
<link rel="preload" href="gibberish.js">
2.1.5:XHTML中的变化
可扩展超文本标记语言(XHTML,Extensible HyperText Markup Language)是将HTML作为XML的应用重新包装的结果。与HTML不同,在XHTML中使用JavaScript必须指定type属性且值为text/javascript,HTML中则无这属性。XHTML虽然已经推出历史的舞台,但实践中偶尔可能会遇到遗留的代码
-
在XHTML编写规则比HTML严格的多
-
影响使用<脚本script>元素嵌入JavaScript代码。
-
例子如下:
<script type="text/javascript"> function compare(a, b) { if (a < b) { console.log("A is less than B"); } else if (a > b) { console.log("A is greater than B"); } else { console.log("A is equal to B"); } } </script>在HTML中,解析<脚本script>元素会应用特殊规则。XHTML中则没有这种规则,意味 a < b语句中的小于号(<)会被解析成一个标签的开始,并且由于作为标签开始的小于号后面不能有空格,这样会导致语法的错误。
避免XHTML中这种语法错误分为两种:
- 把所有小于号(<)都替换成对应的HTML实体形式
- 把所有代码都包含到一个CDATA块中。在XHTML(及XML)中,CDATA块表示文档中可以包含任意文本的区块,其内容不作为标签来解析,因此可以在其中包含任意字符,包括小于号
1:<script type="text/javascript"> function compare(a, b) { if (a < b) { console.log("A is less than B"); } else if (a > b) { console.log("A is greater than B"); } else { console.log("A is equal to B"); } } </script>2:<script type="text/javascript"><![CDATA[ function compare(a, b) { if (a < b) { console.log("A is less than B"); } else if (a > b) { console.log("A is greater than B"); } else { console.log("A is equal to B"); } } ]]></script>
2.2:行内代码与外部文件
虽然可以直接在HTML文件中嵌入JavaScript代码,但通常认为最佳实践就是尽可能将JavaScript代码放在外部文件中,几个理由如下:
- 可维护性:JavaScript代码如果分散到很多HTML页面,会导致维护困难。而用一个目录保存所有的JavaScript文件,则容易维护,这样开发者就可以独立于使用它们的HTML页面来编辑代码
- 缓存:浏览器会根据特定的设置缓存所有外部链接的JavaScript文件,这意味着如果两个页面都用到同一个文件,则该文件只需下载一次,也意味着加载速度提高
- 适应未来:通过把JavaScript放到外部文件中,就不需要考虑用XHTML
重点🤔: 配置浏览器请求外部文件考虑的一点是会占用多少宽带。在SPDY/HTTP2中,预请求的消耗已显著降低,以轻量、独立JavaScript组件形式向客户端送达脚本更具优势.
比如,第一个页面包含如下脚本:
<script src="mainA.js"></script>
<script src="component1.js"></script>
<script src="component2.js"></script>
<script src="component3.js"></script>
后续页面可能包含如下脚本:
<script src="mainB.js"></script>
<script src="component3.js"></script>
<script src="component4.js"></script>
<script src="component5.js"></script>
1:在初次请求时,如果浏览器支持SPDY/HTTP2,就可以从同一个地方获取一批文件,并将它们逐个放入浏览器缓存中,从浏览器角度看,通过SPDY/HTTP2获取所有这些独立资源于获取一个大JavaScript文件的延迟差不多
2:第二个页面请求时,以及把应用程序切割成轻量缓存的文件,第二个页面也依赖某些组件此时已经存在浏览器缓存中
3:这是假设浏览器都支持SPDY/HTTP2,只有比较新的浏览器才有。
2.3:文档模式
IE5发明了文档模式概念,即可以使用doctype切换文档模式,最初的文档只有两种:
- 混杂模式(quirks mode)
- 标准模式(standards mode)
IE初次支持文档模式切换后,其他浏览器也跟着实现,随着浏览器的普遍实现,又出现了第三种文档模式: 准标准模式(almost standards mode)。这种模式下的浏览器支持喝多标准特性,但没有标准那么严格.
混杂模式在所有浏览器中都以省略文档开头的doctype声明作为开关.这种约定并不合理,因为混杂模式在不同的浏览器中的差异非常大,不使用黑科技基本上没有浏览器一致性可言
标准模式通过下列几种文档类型声明开启:
<!-- HTML 4.01 Strict -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<!-- XHTML 1.0 Strict -->
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- HTML5 -->
<!DOCTYPE html>
准标准模式通过过渡性文档类型(Transitional) 和框架集文档类型(Frameset)来触发:
<!-- HTML 4.01 Transitional -->
<!DOCTYPE HTML PUBLIC 5 "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<!-- HTML 4.01 Frameset -->
<!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Frameset//EN"
"http://www.w3.org/TR/html4/frameset.dtd">
<!-- XHTML 1.0 Transitional -->
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- XHTML 1.0 Frameset -->
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
[区分] 准标准模式与标准模式非常接近,很少需要区分,人们说到"标准模式"的时候,可能指其中任意一个。
2.4:<\noscript/>元素
针对早期浏览器不支持JavaScript问题,需要一个页面优雅降级的处理方式,最终,<\noscript/>元素出现,被用于给不支持JavaScript的浏览器提供替代内容,这个元素直到现在仍然有它的用处
它可以包含任何可以出现在<#body#>中的HTML元素,<脚本script>除外。浏览器将显示包含在<\noscript/>中的内容分为两种情况:
- 浏览器不支持脚本
- 浏览器对脚本的支持被关闭
任何一个条件被满足的时候,包含在<\noscript/>中的内容就会被渲染,否则,浏览器不会渲染这个元素中的内容。例子:
<!DOCTYPE html>
<html>
<head>
<title>Example HTML Page</title>
<script defer="defer" src="example1.js"></script> <script defer="defer" src="example2.js"></script> </head>
<body>
<noscript>
<p>This page requires a JavaScript-enabled browser.</p> </noscript>
</body>
</html>
大总结:
JavaScript时通过<脚本script>元素插入到HTML页面中,这个元素可以用于JavaScript代码嵌入到HTML页面中,跟其他标记混合在一起,也可以用于引入保存在外部文件中的JavaScript.
- 要包含外部JavaScript文件,必须把src属性设置为要包含文件的URL,文件可以跟网页在同一个服务器上,也可以在不同的域中
- 所有<脚本script>元素会依照它们在网页中出现的次序被解析,在不使用defer和async属性的情况下,包含在<脚本script>元素必须被依次解析
- 对不推迟执行的脚本,浏览器必须解析完位于<脚本script>元素中的代码,然后才能继续渲染页面的剩余部分,为此,通常应该把<脚本script>元素放在页面末尾,介于住内容之后及标签之前
- 可以使用defer属性把脚本推迟到文档渲染后再执行,推迟的脚本原则上按照它们被列出的顺序进行依次执行
- 可以使用async属性表示脚本不需要等待其他脚本,同时不阻塞文档渲染,即异步加载,异步脚本不能保证按照依次执行顺序
- 通过<\noscript/>元素,可以指定在浏览器不支持脚本时显示内容,如果浏览器支持并启用脚本,则<\noscript/>元素中的任何内容不会被渲染
感想:学到了第三天越来越发现万事真的开头难,想放弃,但是茶水加奕迅打鸡血,加油