JavaScript的加载与执行

    javascript

  1. 加载与执行的特点
  2. 异步加载的可能
    1. async
    2. 动态创建DOM
    3. 终极方式

加载与执行的特点

  • 加载好即执行
  • 阻塞浏览器后续动作(渲染页面、加载其他资源。。。)

所以,很多网站会把script标签放在页面最下或者onload回调里

异步加载的可能

async

MDN Web Docs上的描述:

1
2
3
4
5
async

For classic scripts, if the async attribute is present, then the classic script will be fetched in parallel to parsing and evaluated as soon as it is available.

For module scripts, if the async attribute is present then the scripts and all their dependencies will be executed in the defer queue, therefore they will get fetched in parallel to parsing and evaluated as soon as they are available.

里面有个模棱两可的说法:

1
as soon as ... available

这里的 as soon as 就很迷,一旦、尽快。那到底是什么时候?

测试一下,加了async的script标签里的普通js会正常加载,并不影响后续其他资源的加载和页面的渲染。进一步观察,当页面所需资源都加载好,若此时async的script标签也加载好了,则会立即执行里面的脚本。所以,执行时机还是不确定。

动态创建DOM

1
2
3
4
5
6
7
8
9
10
var script = document.createElement("script")
script.setAttribute("type", "text/javascript")
script.setAttribute("src", "xx.js")
script.setAttribute("id", "xx_script_id")
script_id = document.getElementById("xx_script_id")
if (script_id) {
document.getElementsByTagName("head")[0].removeChild(script_id)
}

document.getElementsByTagName("head")[0].appendChild(script)

跑下题,这就是JSONP的实现方式。
用script标签加载接口,接口返回数据作为参数传递给回调方法。

1
<script type="text/javascript" src="http://server2.example.com/RetrieveUser?UserId=1823&jsonp=parseResponse"></script>
1
parseResponse({"Name": "小明", "Id" : 1823, "Rank": 7})

回到异步加载。创建DOM解决了“想什么时候加载就什么时候加载”的问题,但并没解决“想什么时候执行就什么时候执行”的问题。

我们退而求其次,将动态创建DOM绑定到某个事件(onload、onclick…)上,当触发该事件时加载并执行js。

终极方式

利用浏览器缓存。直接在某个合适时机通过XMLHttpRequest或fetch请求一次js,让浏览器缓存住。当然,动态创建DOM去加载的步骤还是不能省。

1
2
3
4
// 都不必处理readystatechange事件
var xhr = new XMLHttpRequest()
xhr.open('GET', 'xxx.js')
xhr.send('')
page PV:  ・  site PV:  ・  site UV: