关于<script>
在HTML中的位置问题
今天在做Ajax发送POST请求实验时遇到了一个由于<script>
位置放错导致的错误。
代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>AJAX发送请求</title>
</head>
<script>
var btn = document.getElementById("btn");
var textusername = document.getElementById("username");
var textpassword = document.getElementById("password");
btn.onclick = function(){
//获取界面上的元素value
var username = textusername.value;
var password = textpassword.value;
//通过XMLHttpRequest发送POST请求
var xhr;
xhr = new XMLHttpRequest();
xhr.open("POST","LoginServlet");
//如果请求体是urlencoded格式,必须设置这个请求头
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xhr.send("username=" + username + "& password=" + password);
xhr.onreadystatechange = function(){
if(this.readyState != 4) return;
document.getElementById("result").innerHTML = xhr.responseText;
}
}
</script>
<body>
<table border="1">
<tr>
<td>用户名</td>
<td><input type="text" id="username" name="username"></td>
</tr>
<tr>
<td>密码</td>
<td><input type="password" id="password" name="password"></td>
</tr>
<tr><td><button type="button" id="btn">登录</button></td>
<td><label id="result"></label></td></tr>
</table>
</body>
</html>
结果:浏览器控制台报错Uncaught TypeError:Cannot set prioerty ‘onclick’ of full
解决方案:百度说是<script>
位置的问题,于是试着把<script>
代码块的内容放到了</body>
标签之后,结果没有报错了。
问题所在:这里的<script>
脚本需要访问到dom元素,但此时还未生成dom元素,所以报错。
原理: HTML是自上而下加载页面的,但引入的css和javascript的顺序有所不同,css引入执行加载时,程序仍然往下执行,而执行到
<script>
脚本时则中断线程,待该script脚本执行结束之后程序才继续往下执行。
<script>
应该放在HTML的什么位置呢?(由百度和知乎所得)
- 对于必须在DOM加载之前运行的脚本,放在
<head>
标签中。但要确保内敛的这些脚本很小,最好是压缩过的,并且执行速度很快,不会造成浏览器渲染的阻塞。 - 对于需要访问DOM的脚本,放在
<body>
标签中。 - 使用
<script>
标签的async和defer属性。
- async实现脚本的异步加载(仅适用于外部脚本,即使用src属性时),不会阻塞浏览器对页面的渲染,但带有async属性的脚本不能保证它们执行的前后顺序。
下面是摘自W3school的例子:
<!DOCTYPE html>
<html>
<body>
<p id="p1">Hello World!</p>
<script type="text/javascript" src="/example/html5/demo_async.js" async="async"></script>
</body>
</html>
- defer实现脚本的延时加载(仅适用于外部脚本,即使用src属性时),脚本会被延迟至整个页面解析完成后再执行。
下面是摘自W3school的例子:
<html>
<body>
<script type="text/javascript" defer="defer">
alert(document.getElementById("p1").firstChild.nodeValue);
</script>
<p>上面的脚本会从下面的段落中请求信息。通常,这是做不到的,因为在段落加载之前,脚本已经运行过了。</p>
<p id="p1">Hello World!</p>
<p>然而,defer 属性规定了脚本必须在页面加载完毕后执行。这样,脚本就可以从段落中请求数据了。</p>
<p><b>注释:</b>该属性只能在 Internet Explorer 中运行。</p>
</body>
</html>
关于 <script>
放在<body>
结束标签之后<html>
标签之前 还是 <body>
结束标签之前
测试发现这两种方法的结果都没有区别。根据HTML5标准中出现的HTML语法规则,如果在</body>
后再出现<script>
或任何元素的开始标签,都是parse error,浏览器会忽略之前的</body>
,即视作仍旧在body内,最终的DOM树里,<script>
元素还是会成为body的子节点。虽然把<script>
放在<body>
结束标签之后<html>
标签之前也没报错,但是这不符合标准,而且没有带来任何好处,所以不建议这样做。
参考文章:
为什么把 Script 标签放在 body 结束标签之后 html 结束标签之前?
该把JS文件放在HTML文档的那个位置