梦秋雨 2019-07-01
可以理解为:只有在JS线程中没有任何同步代码要执行的前提下才会执行异步代码
首先明确,浏览器的内核是多线程的,它们在内核制控下相互配合以保持同步,一个浏览器至少实现三个常驻线程:
JavaScript 引擎是单线程运行的,浏览器无论在什么时候都只且只有一个线程在运行JavaScript程序
在具备了上述理论基础之后,我们对以下几个实例进行分析:
===========================================
var t = true;
window.setTimeout(function (){
t = false;
},1000);
while (t){}
alert('end');运行结果:程序陷入死循环,t = false 得不到执行,因此 alert('end') 不会执行。
解析:
===========================================
var start = new Date();
setTimeout(function(){
var end = new Date();
console.log("Time elapsed: ", end - start, "ms");
}, 500);
while (new Date - start <= 1000){}运行结果:"Time elapsed: 1035 ms" (这里的1035不准确 但是一定是大于1000的)
解析:
===========================================
for(var i=0;i<10;i++){
setTimeout(function() {
console.log(i);
}, 0);
}运行结果:输出10个10
解析:JS单线程 setTimeout 异步代码 任务队列
问:如何修改可以使上述代码输出 0123456789
自执行函数 或 使用ES6中的let关键字
// 自执行函数 形成闭包 记忆其被创建时的环境
for(var i=0;i<10;i++){
setTimeout((function() {
console.log(i);
})(), 0);
}现在我们了解了setTimeout函数执行的原理,那么它有什么作用呢?
setTimeout函数增加了Javascript函数调用的灵活性,为函数执行顺序的调度提供极大便利。
简言之,改变顺序,这正是setTimeout(0)的作用。
使用场景示例:
<input type="text" onkeydown="show(this.value)">
<div></div>
<script type="text/javascript">
function show(val) {
document.getElementsByTagName('div')[0].innerHTML = val;
}
</script>这里绑定了 keydown 事件,意图是当用户在文本框里输入字符时,将输入的内容实时地在 <div> 中显示出来。但是实际效果并非如此,可以发现,每按下一个字符时,<div> 中只能显示出之前的内容,无法得到当前的字符。
修改代码:
<input type="text" onkeydown="var self=this; setTimeout(function(){show(self.value)}, 0)">
<div></div>
<script type="text/javascript">
function show(val) {
document.getElementsByTagName('div')[0].innerHTML = val;
}
</script>这段代码使用setTimeout(0)就可以实现需要的效果了。
这里其实涉及2个任务,1个是将键盘输入的字符回写到输入框中,一个是获取文本框的值将其写入div中。第一个是浏览器自身的默认行为,一个是我们自己编写的代码。很显然,必须要先让浏览器将字符回写到文本框,然后我们才能获取其内容写到div中。改变顺序,这正是setTimeout(0)的作用。
其他应用场景:有时候,加载一些广告的时候,我们用setTimeout实现异步,好让广告不会阻塞我们页面的渲染。