你真的会用setTimeout吗?

2018-1-30 15:15:27 3,085 views

关于setInterval()和setTimeout()返回值

setInterval(),setTimeout() 会返回一个值,一般认为是ID,将这个ID值传递给clearInterval(),clearTimeout() 可以取消执行,例如:

js 代码:

var intervalTimer=setInterval(function(){
console.log(1)
},3000);
console.log(intervalTimer); //一般是一个数字,Number
button.onclick=function(){
clearInterval(intervalTimer);
};

关于setTimeout的作用域

关于setInterval()和setTimeout()中回调函数中的this

setInterval(),setTimeout() 方法是浏览器 

window

 对象提供,所以第一个参数函数中的

this

指向

window

对象,这跟变量的作用域有关:

js高程:超时调用的代码都是在全局作用域中执行的,因此函数中this值在非严格模式下指向window对象,在严格模式下是undefined;
js 代码:

var a=1;
var obj={
a:2,
b:function(){
setTimeout(function(){
console.log(this.a);//这里返回的是:1;
},2000);
}
};
obj.b();

当然你可以通过使用bind()方法来改变这个情况:当然也可以用call或者apply

js 代码:

var a=1;
var obj={
a:2,
b:function(){
setTimeout(function(){
console.log(this.a);//这里返回的是:2;
}.bind(this),2000);//注意这行
 
}
};
obj.b();

 

关于setInterval()和setTimeout()的参数

大家都知道setInterval()和setTimeout()可以接收两个参数,第一个参数是需要回调的函数,必须传入的参数,第二个参数是时间间隔,毫秒数,可以省略,这个可以看文章的下面,

不传第二个参数,浏览器自动配置时间,在IE,FireFox中,第一次配可能给个很大的数字,100ms上下,往后会缩小到最小时间间隔,Safari,chrome,opera则多为10ms上下。

但是我要说的当然不是这个,我要说的是setInterval()和setTimeout()可以接收更多的参数,那么这些参数是干什么用的呢?从第三个参数开始,依次用来表示第一个参数(回调函数)传入的参数,例如:

js 代码:

setTimeout(function(a,b){
console.log(1+a+b);//这里打印的是:8
},1000,3,4);

 

当然一些古老的浏览器是不支持的。  ie10+

关于clearInterval()和clearTimeout()

clearInterval()和clearTimeout()其实是通用的,就是说你可以用 clearInterval() 取消 setTimeout() 执行,clearTimeout()同样可以取消 setInterval() 执行。

js 代码:

var intervalTimer=setInterval(function(){
console.log(1)
},3000);
console.log(intervalTimer);
button.onclick=function(){
clearTimeout(intervalTimer); //注意这里,不是clearInterval哦
};

 

=============== 以下内容来源: 你会用setTimeout吗  ===================

教科书里面的setTimeout

定义很简单
setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式。
广泛应用场景
定时器,轮播图,
缓冲动画 http://www.cnblogs.com/yi-mi-yangguang/p/6362648.html
动画完美框架 http://www.cnblogs.com/yi-mi-yangguang/p/6375760.html
无缝滚动 http://www.cnblogs.com/yi-mi-yangguang/p/6389403.html
上面一些应该是setTimeout在大家心中的样子,因为我们平常使用也不是很多。
但是setTimeout真的有那么简单吗?
测试题
一个题目,如果你在一段代码中发现下面内容

js 代码:

var startTime = new Date();
setTimeout(function () {
console.log(new Date() - startTime);
}, 100)

 

请问最后打印的是多少?

我觉得正确答案是,取决于后面同步执行的js需要占用多少时间。

MAX(同步执行的时间, 100)


再加一个题目,只有下面代码

js 代码:

setTimeout(function () {
func1();
}, 0)
func2();

 

func1和func2谁会先执行?

这个答案应该比较简单,func2先执行,func1后面执行。
再来一题

js 代码:

setTimeout(function () {
func1()
}, 0)

 

js 代码:

setTimeout(function () {
func1()
})

 

有什么差别?

0秒延迟,此回调将会放到一个能立即执行的时段进行触发。javascript代码大体上是自顶向下的,但中间穿插着有关DOM渲染,事件回应等异步代码,他们将组成一个队列,零秒延迟将会实现插队操作。
不写第二个参数,浏览器自动配置时间,在IE,FireFox中,第一次配可能给个很大的数字,100ms上下,往后会缩小到最小时间间隔,Safari,chrome,opera则多为10ms上下。

上面答案来自《javascript框架设计》
好了,看了上面几个题目是不是感觉setTimeout不是想象中那样了。

setTimeout和单线程

如果你不了解js的运行机制可以看看这 http://www.suanliutudousi.com/2017/09/25/javascript-%E8%BF%90%E8%A1%8C%E6%9C%BA%E5%88%B6%E8%AF%A6%E8%A7%A3%EF%BC%9Aevent-loop/
下面是我自己的一些理解
首先需要注意javascript是单线程的,特点就是容易出现阻塞。如果一段程序处理时间很长,很容易导致整个页面hold住。什么交互都处理不了怎么办?
简化复杂度?复杂逻辑后端处理?html5的多线程?
上面都是ok的做法,但是setTimeout也是处理这种问题的一把好手。
setTimeout一个很关键的用法就是分片,如果一段程序过大,我们可以拆分成若干细小的块。
例如上面的情况,我们将那一段复杂的逻辑拆分处理,分片塞入队列。这样即使在复杂程序没有处理完时,我们操作页面,也是能得到即使响应的。其实就是将交互插入到了复杂程序中执行。
换一种思路,上面就是利用setTimeout实现一种伪多线程的概念。
有个函数库

Concurrent.Thread.js

 就是实现js的多线程的。
 

Concurrent.Thread.js

链接: https://pan.baidu.com/s/1kW3BMTp 密码: 7ph7
一个简单使用的例子,引入

Concurrent.Thread.js


想体验下?点击
第一个例子是使用了

Concurrent.Thread.js的

http://www.suanliutudousi.com/test/demo/18-1-30/thread.html 
第二个例子是没有使用的,慎入!!  浏览器可能直接卡死
http://www.suanliutudousi.com/test/demo/18-1-30/normal.html
 

html代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>JavaScript多线程</title>
    <style type="text/css">
      div {
        width: 100px;
        height: 100px;
        cursor: pointer;
        background: orange;
      }
    </style>
  </head>
  <body>
    <div id="test">
      测试点击
    </div>
    <script type="text/javascript" src="js/Concurrent.Thread.js"></script>
    <script type="text/javascript">
      Concurrent.Thread.create(function() {
        var test = document.getElementById("test");
        test.onclick = function() {
          alert(1);
        }
        /*下面有一段特别复杂的函数*/
        for(var i = 0; i < 100000; i++) {
          console.log(i);
        }
      });
    </script>
  </body>
</html>

 

 

虽然有个巨大的循环,但是这时不妨碍你去触发alert();
是不是很厉害~
还有一种场景,当我们需要渲染一个很复杂的DOM时,例如table组件,复杂的构图等等,假如整个过程需要3s,我们是等待完全处理完成在呈现,还是使用一个setTimeout分片,将内容一片一片的断续呈现。
其实setTimeout给了我们很多优化交互的空间。

如何使用

setTimeout这么厉害,那么我们是需要在在项目中大量使用吗?
我这边的观点是非常不建议,在我们业务中,基本上是禁止在业务逻辑中使用setTimeout的,因为我所看到的很多使用方式都是一些问题不好解决,setTimeout作为一个hack的方式。
例如,当一个实例还没有初始化的前,我们就使用这个实例,错误的解决办法是使用实例时加个setTimeout,确保实例先初始化。
为什么错误?这里其实就是使用hack的手段
第一是埋下了坑,打乱模块的生命周期
第二是出现问题时,setTimeout其实是很难调试的。
我认为正确的使用方式是,看看生命周期(可参考《关于软件的生命周期 》),把实例化提到使用前执行。
综上,setTimeout其实想用好还是很困难的, 他更多的出现是在框架和类库中,例如一些实现Promis的框架,就用上了setTimeout去实现异步。
所以假如你想去阅读一些源码,想去造一些轮子,setTimeout还是必不可少的工具。
 
以上内容摘自http://www.css88.com/archives/5804  并结合了自己的理解

1

分享到微信朋友圈

打开微信,点击底部的“发现”,
使用“扫一扫”即可将网页分享至朋友圈。