在Google为其API提供的各种javascript示例中(例如here),他们使用以下代码从html加载脚本:
<script async defer src="https://apis.google.com/js/api.js"
onload="this.onload=function(){};handleClientLoad()"
onreadystatechange="if (this.readyState === 'complete') this.onload()">
</script>
我的理解是async/defer
告诉浏览器何时加载和执行脚本并且彼此有些矛盾。我几乎没有问题:
async
和defer
的含义是什么?
上下文?onload
事件中,为什么他们首先为事件分配一个空函数(function(){};
)
在致电handleClientLoad()
之前?感谢。
答案 0 :(得分:2)
the WHAT-WG living standard for HTML's section on async
and defer
完全涵盖了这一点,其中包括这个方便的图形:
1。在这种情况下同时使用async和defer是什么意思?
如果浏览器支持async
,则会忽略defer
并执行异步操作。如果没有,但它支持defer
,则会延迟。如果它也不支持,脚本会阻止DOM解析,但所有现代浏览器都支持至少一个。
2.为什么谷歌选择使用这种技术?它有任何表现或其他好处吗?
async
在不阻止DOM解析和呈现的情况下获取脚本,并在可用时立即运行,即使DOM解析和呈现仍在进行中。 defer
也将避免阻止DOM解析和呈现,但在解析完成之前不会运行脚本(例如,可能稍后)。
3。在onload事件中,为什么他们在调用
function(){};
之前首先为事件分配一个空函数(handleClientLoad()
?)
如果你看onreadystatechanged
,这一点就变得清晰了:基本上它确保handleClientLoad
只被GAPI调用一次,而不是两次(一次由onload
调整一次,一次调用onreadystatechanged
}。)
4。如果我想将整个javascript移动到单独的js文件,那么加载这两个脚本的最佳方法是什么?由于新的js文件将依赖于api.js并且无法异步加载?
好吧,可以异步加载,你只需要用api.js
来处理竞争条件。我可能会:
在handleClientLoad
标记加载script
之上的内联脚本中加api.js
,如下所示:
var clientLoaded = false;
function handleClientLoad() {
if (!clientLoaded &&
typeof mainScriptLoad !== "undefined" &&
typeof gapi !== "undefined") {
clientLoaded = true;
mainScriptLoad();
}
}
在单独的文件中添加mainScriptLoad
。
在单独文件的末尾,请致电handleClientLoad
。
那样:
handleClientLoad
,但handleClientLoad
会看到GAPI尚未加载且不会执行任何操作;之后,当加载GAPI时, 将调用handleClientLoad
,这将调用mainScriptLoad
,因为一切准备就绪。handleClientLoad
,但handleClientLoad
会看到您的主脚本尚未加载,而不是尝试调用它。稍后,当您的脚本加载并调用handleClientLoad
时,handleClientLoad
会调用mainScriptLoad
,因为一切准备就绪。