同步模式,又称阻塞模式,会阻止浏览器的后续处理,停止了后续的解析,因此停止了后续的文件加载(如图像)、渲染、代码执行。
js 之所以要同步执行,是因为 js 中可能有输出 document 内容、修改dom、重定向等行为,所以默认同步执行才是安全的。
js默认是同步模式,所以我们一般写在</body>之前,因为我们一旦遇到这样的js代码,就得停下来加载。
想想我们打开一个页面时,什么都没有,你还想用它吗?肯定是最基础的html,css得加载出来吧。
js异步加载的缺点:有一些加载工具方法,没必要阻塞文档,过多的js加载会影响页面效率,一旦网速不好,那么整个网站都会等待js加载而不进行渲染工作。
js实现异步加载有三种方法:
1:defer
defer异步加载,但要等到dom文档全部解析完才会被执行。只有IE可以用,也可以将代码写到script标签内部。
<script type='text/javascript' src='jq.js' defer='defer'></script>
那么这个时候遇到了,不会停下来加载js文件,而是重新再启动一个线程来加载这个文件。
执行时刻是文档被解析完时。
2.async异步加载,加载完成时,就执行。async只能加载外部脚本,不能把js写到script标签里面。
IE9以上兼容。
<script type='text/javascript' src='jq.js' async='async'></script> <script type='text/javascript' async='async'> var a=3; </script>
第二个是错误的,不能在里面写代码。其他和第一个一样。
3.
onload事件。当对象加载完成时就执行。
但是IE上的script标签上没有这个,它提供了一个状态码readyState 它里面存着一些状态。
script.readyState 一开始存'loading' ,加载完成是'complete' 或者'loaded'.
IE还提供了一个事件 onreadystatechange,但readystate发现改变时,那么就触发。
var script=document.createElement('script'); script.style='text/javascript'; script.src='jq.js'; scrip.onreadystatechange =function() { if (script.readyState=='complete'||script.readyState='loaded') { //执行 } }
我们封装一个函数,当我们需要异步加载某个js的文件时,然后加载完成时执行某个函数callBack(加载文件里面的函数)
function loadScript(url,callBack) { var script=document.createElement('script'); script.style='text/javascript'; if (script.readyState) { script.onreadystatechange=function() { if (script.readyState=='complete'||script.readyState=='loaded') { callBack(); } } } else { script.onload =function() { callBack(); } } script.src=url;//我们先绑定事件,再加载文件,因为如果先加载,万一文件很小,加载完了,下面代码还没执行,readyState就变了,就尴尬了。 document.head.appendChild(script); }
这样,我们如果调用的时候就得这样写。
loadScript('jp.js',function() { //需要执行的函数 });
也可以传字符串进出,那么用eval来解决。
为什么了?很明显,如果我们直接将函数引用写上去,文件都没有加载出来,函数引用哪里来的?我们套一层函数,预处理的时候,就不会管函数里面的代码是什么内容。