Javascript学习---调度:setTimeout&&setInterval

setTimeout&&setInterval

有时候我们不想要马上执行函数,而是在未来的特定时间里执行,这就涉及到调度问题,Javascript提供了setTimeout和setInterval这两个函数:

(1)setTimeout:允许在指定的时间间隔之后执行函数(一次);

(2)setInterval:允许在运行期间定期地执行函数(多次);


setTimeout

setTimeout的语法如下:

let timerId = setTimeout(func|code, delay[, arg1, arg2...])

其中func|code需要执行的函数或字符串代码;delay是延迟运行的时间,以毫秒为单位;arg1,arg2...指定是被调度函数的参数。


延迟一秒后执行的例子:

function sayHi() {
  alert('Hello');
}

setTimeout(sayHi, 1000);

设置执行函数参数:

function sayHi(phrase, who) {
  alert( phrase + ', ' + who );
}

setTimeout(sayHi, 1000, "Hello", "John"); // Hello, John


如果setTimeout的第一个参数是字符串代码,则Javascript默认根据代码生成一个函数,例如:

setTimeout("alert('Hello')", 1000);

但是使用字符串代码的形式是不推荐的,我们可以使用箭头函数来代替它,例如:

setTimeout(() => alert('Hello'), 1000);


需要注意的是,有时候我们可能会在执行函数后面加多个括号“()”,这样setTimeout函数会报错,例如:

// wrong!
setTimeout(sayHi(), 1000);  //undefined

这是因为setTimeout接受的是一个函数的引用,引用的值会传递给setTimeout。但如果是一个函数的话,由于sayHi()不返回任何值,故没有传递值给setTimeout,所以结果是undefined


取消调度clearTimeout

我们使用setTimeout来设置调度后,也可以通过clearTimeout来取消调度,例如:

let timerId = setTimeout(...);
clearTimeout(timerId);

由于每次使用setTimeout后都会默认返回一个标识符,所以取消调度的会则要通过这个标识符


再看下面的例子:

let timerId = setTimeout(() => alert("never happens"), 1000);
alert(timerId); // timer identifier

clearTimeout(timerId);
alert(timerId); // same identifier (doesn't become null after canceling)

从上面的结果中可以看出,在浏览器中timerId是一个数字,而在其他环境中可能会是其他类型数据,例如在Node.js会返回一个附带其他方法的timer对象


setInterval

setInterval和setTimeout有一样的语法:

let timerId = setInterval(func|code, delay[, arg1, arg2...])

但是有一点不同的是setInterval会在时间间隔后定期执行,不是只有一次


为了取消setInterval,我们可以使用clearInterval,例如:

// repeat with the interval of 2 seconds
let timerId = setInterval(() => alert('tick'), 2000);

// after 5 seconds stop
setTimeout(() => { clearInterval(timerId); alert('stop'); }, 5000);

递归的setTimeout

前面我们已经知道了,setTimeout仅仅执行一次,为了达到setInterval的效果,我们可以递归地使用setTimeout,例如:

/** instead of:
let timerId = setInterval(() => alert('tick'), 2000);
*/

let timerId = setTimeout(function tick() {
  alert('tick');
  timerId = setTimeout(tick, 2000); // (*)
}, 2000);
相比于setInterval,递归使用setTimeout可能更加灵活,因为我们还可以在递归中修改delay时间


递归使用setTimeout严格保证了执行函数被调度的时间间隔,而setInterval却不能严格保证,看下面两个例子:

let i = 1;
setInterval(function() {
  func(i);
}, 100);
let i = 1;
setTimeout(function run() {
  func(i);
  setTimeout(run, 100);
}, 100);

第一个例子中,func()会在每隔100毫秒后被调用,无论func()有没有执行完,若func()执行时间大于间隔时间,那么就会出现叠加调用的情况,即第一次调用的func()还没执行完,func()的第二次调用就开始了;第二个例子中,func()每次执行完后的100毫秒后再次被调用。因此,我们应该根据具体情况使用setInterval和递归的setInterval


setTimeout(…,0)情况

这里有一个特殊的情况,当使用setTimeout(...,0)时,它会在当前的其他代码执行完后再执行,也就是异步,例如:

setTimeout(() => alert("World"), 0);

alert("Hello");
这里它会先输出"Hello",再输出"World"




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值