从setTimeout()看到js异步机制
格式
var timeoutID = window.setTimeout(func, [delay, param1, param2, ...])
指的是若干毫秒后执行func,大概是一个闹钟的功能; MDN手册
值得注意的问题
以前想过setTimeout(func,0)指的是不是立即执行呢? 下面看个例子:
alert(1);
setTimeout(function(){
alert(2);
},0);
alert(3);
结果却是
1
3
2
是不是感到很奇怪,这个意思就是setTimeout(func,0)并不是立即执行;
在网上查了资料,发现这个要从js引擎说起
js引擎的单线程性
首先区分两个概念: js引擎和浏览器内核
js引擎是单线程的这个没错,但是,就因为js引擎是单线程的,它没法再为其他功能服务; 同时,浏览器是多线程的,这就说的通了:比如浏览器事件触发、定时器计时、网络请求、渲染等都是由浏览器内核分配的其他线程完成的,js引擎只占其中一个线程。
再举个经典例子:
var end = ture;
window.setTimeout(function(){
end = false;
},1000);
while(end);
alert('end');
上面的例子结果就是 while(end)处死循环,永远到不了alert(‘end’),意思就是setTimeout里边的函数没有执行;
下面就引入这个事件队列的问题,用一张图表示:
js是基于事件驱动的语言,所以遵循一个叫事件队列的机制。从图中可看出浏览器的各种各样的线程,比如事件触发器、网络请求、定时器等,js引擎处理到与其他线程相关的代码,会把他们分发到其他线程,他们处理完后需要js引擎计算时就是在事件队列添加一个任务。然而在这个过程中,js并不会阻塞代码等待其他线程执行完毕,而是直接跳过这个分发给别的进程的代码,执行下一串代码。
很明显上面while(end)的死循环问题就得到解决,执行到setTimeout的时候,把这个东西(定时器)扔到了事件队列后边,然后执行while(end)但这时end是true,所以造成死循环,与第一个setTimeout(func,0)的例子一样得到解释。
<link rel="prefetch" href="http://"> <!--利用空余时间加载剩下的网页-->
2.HTML5的defer async标签实现异步加载
<script defer="true" type="text/javascript"></script><!--不等js加载完成就加载后边的图片-->
<script async="true" type="text/javascript"></script>
3.动态加载js
document.write("<script src="a.js"></script>");
/*还有修改src路径、创建script标签再将其放进DOM中,这些都是对DOM操作*/
setTimeout(func,0)特殊功效
换个角度想,是不是可以用setTimeout(func,0)强行将func放到队列后边延迟执行呢?!这也算是个小技巧吧?
而这个技巧在同样情况下(打开一个标签,就测试环境差不多)不同浏览器上出现的时间会不同,我个人认为这也可以看出浏览器的性能;
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!