为了解释上面的那句话,来个简单的小例子:javascript
<!DOCTYPE html>
<head>
<title>setTimeout</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<h1>setTimeout</h1>
<span id="content">测试</span>
<script>
setTimeout(function () {
let content = document.getElementById('content');
content.innerHTML = "<div>一秒后</div>";
},1000);
</script>
</body>
</html>
复制代码
span标签里面的内容一秒以后由“测试”变成了“一秒后”。html
来实现了:java
<!DOCTYPE html>
<head>
<title>setTimeout</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<h1>setTimeout</h1>
<span id="content">时间</span>
<button onclick="start()">开始</button>
<script>
var x = 00,
y = 00,
z = 00;
function start () {
if (x<= 59 && x>=0 && y<=59 && y>=0 && z<=59 && z>=0) {
let content = document.getElementById('content');
content.innerHTML = z + ":" + y + ":" + x;
console.log(x);
x = x + 1;
} else if (y<=59 && y>=0 && z<=59 && z>=0) {
y = y + 1;
x = 0;
} else if (z<=59 && z>=0){
z = z + 1;
x = 0;
y = 0;
}
setTimeout ("start()",1000); //注意,这里调用要用引号包围
}
</script>
</body>
</html>
复制代码
控制台输出: 面试
这里点击以后执行start()函数,在函数里面setTimeout()函数又调用了start(),因此就是一秒钟调用一次start()函数。ajax
你们都知道setInterval()和setTimeout()能够接收两个参数,第一个参数是须要回调的函数,必须传入的参数,第二个参数是时间间隔,毫秒数,能够省略。但其实他能够接收更多的参数,那么这些参数是干什么用的呢?从第三个参数开始,依次用来表示传入回调函数的参数。浏览器
例子:bash
setTimeout(function(a,b){
console.log(0+a+b);//这里打印的是:7
},1000,3,4);
复制代码
若是想向回调函数传参,能够用bind()。
eg:异步
setTimeout( function(a,b){}.bind(3,4), 1000 );
复制代码
setTimeout函数,返回一个表示计数器编号的整数值,将该整数传入clearTimeout函数,就能够取消对应的定时器。函数
clearTimout()有如下语法: clearTimeout(timeoutID)
要使用 clearTimeout( ), 咱们设定 setTimeout( ) 时, 要给予这 setTimout( ) 一个名称, 这名称就是 timeoutID , 咱们叫停时, 就是用这 timeoutID来叫停, 这是一个自定义名称。oop
用法:
var id1 = setTimeout(f,1000); //id1就是timeoutID
var id2 = setInterval(f,1000); //id2就是timeoutID
clearTimeout(id1);
clearInterval(id2);
复制代码
对于javascript中的this指向问题,以前也是困扰了我很久,哎呀,哪儿有那么难嘛,其实一句话就是说:谁调用的就是指向谁啊!意思就是说调用的对象是谁this就是指向谁。
那这样说来个栗子咯:
var x = 1;
var obj = {
x: 2,
y: function(){
console.log(this.x);
}
};
setTimeout(obj.y,1000); // 1
复制代码
why?不是说了哪一个对象调用的就是指向哪一个对象的嘛,这里不是setTimeout函数调用了obj对象里面的y方法吗,那不仍是被setTimeout调用了吗,对啊,没错啊,就是setTimeout调用的,可是setTimeout函数是属于window的,知道吧,因此setTimeout的对象是window,因此一切都明了了。
function Animal(login) {
this.login = login;
this.sayHi = function() {
console.log(this.login); //undefined
}
}
var dog = new Animal('John');
setTimeout(dog.sayHi, 1000);
复制代码
哈哈哈,答对了吧,哇👋,可是没有奖励😂
等到dog.sayHi执行时,它是在全局对象中执行,可是this.login取不到值。
要回答面试官问个人问题了😂。哇,血的教训,来来来 直接一点来栗子吧:
console.log('a');
setTimeout(function(){
console.log('b');
},0);
console.log('c');
console.log('d');
复制代码
控制台输出:
a
c
d
b
我也不截图了。 知道为何吗,理论上他延迟时间为0不是应该立刻执行吗,不是的。由于setTimeout运行机制说过,必需要等到当前脚本的同步任务和“任务队列”中已有的事件,所有处理完之后,才会执行setTimeout指定的任务。也就是说,setTimeout的真正做用是,在“任务队列”的现有事件的后面再添加一个事件,规定在指定时间执行某段代码。setTimeout添加的事件,会在下一次Event Loop执行。好吧,对事件循环不清楚的推荐看看阮一峰-avaScript 运行机制详解
众所周知,Javascript引擎(如下简称JS引擎)是单线程的,在某一个特定的时间内只能执行一个任务,并阻塞其余任务的执行,也就是说这些任务是串行的。这样的话,用户不得不等待一个耗时的操做完成以后才能进行后面的操做,这显然是不能容忍的,可是实际开发中咱们却可使用异步代码来解决。
当异步方法好比这里的setTimeout(),或者ajax请求、DOM事件执行的时候,会交由浏览器内核的其余模块去管理。当异步的方法知足触发条件后,该模块就会将方法推入到一个任务队列中,当主线程代码执行完毕处于空闲状态的时候,就会去检查任务队列,将队列中第一个任务入栈执行,完毕后继续检查任务队列,如此循环。前提条件是主线程处于空闲状态,这就是事件循环的模型。
正经的讲了一波理论,来个栗子吧:
setTimeout(function () {
console.log("b");
},0)
console.log("a");
复制代码
控制台输出:
a
b
原理,就是上面两段话当中解释的,执行时把setTimeout()放入任务队列中去,主线程执行完主线程的任务以后去任务队列里面执行setTimeout出来执行。
同样的道理:
setTimeout(function(){
console.log(1111);
},0)
while (true) {};
复制代码
这里控制台是永远不会输出东西的,由于主线程已经形成了死循环,主线程一直是不会空闲的,他不会到任务队列里面去执行拿setTimeout函数来执行。
推荐一篇文章,更好的理解:完全理解setTimeout()
说了这么多,setTimeout是否是很强大,啊哈哈。可是如不能熟练掌握,不建议多用。毕竟在某些情景之下毕竟在某些情景之下,setTimeout做为一个hack的方式而存在的。
到这里,首先,恭喜你,应该是收获满满了。其次能够点个赞😜