前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >也谈 setTimeout

也谈 setTimeout

作者头像
IMWeb前端团队
发布于 2019-12-04 05:10:27
发布于 2019-12-04 05:10:27
1.3K00
代码可运行
举报
文章被收录于专栏:IMWeb前端团队IMWeb前端团队
运行总次数:0
代码可运行

本文作者:IMWeb 江源 原文出处:IMWeb社区 未经同意,禁止转载

也谈 setTimeout

setTimeout ,延迟一段事件执行代码,当然这是最基本的用法,这里不说基本用法。

jQuery 中的轮询

轮询,可能是 setTimeout 最典型的用法,jQuery 的兼容IE的 document ready 机制就用到了这个:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// jquery 1.9.1
(function doScrollCheck() {
    if ( !jQuery.isReady ) {

        try {
            // Use the trick by Diego Perini
            // http://javascript.nwbox.com/IEContentLoaded/
            top.doScroll("left");
        } catch(e) {
            // 不停地查看是否准备好
            return setTimeout( doScrollCheck, 50 );
        }

        // detach all dom ready events
        detach();

        // and execute any waiting functions
        jQuery.ready();
    }
})();

另外,我还看到了下面这种用法,缺省了 delay 这个参数,不知道会是一个什么状态,待探究。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// jquery 1.9.1
ready: function( wait ) {
    ...

    // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
    if ( !document.body ) {
        return setTimeout( jQuery.ready );
    }

    ...
},

setTimeout( func, 0 )

当然,初见这种用法时,我是一愣啊,什么情况,setTimeout( func, 0 ) 和直接调用 func 难道不是同一个效果?

肯定不是一个效果,在 stackOverflow 也有很多人问。

比如这个Why is setTimeout(fn, 0) sometimes useful?, IE6 中出现的奇葩问题竟然可用 setTimeout(func, 0) 神奇地解决。

这些问题概括来讲是这样:动态往 dom 树中插入元素, 然后立刻、马上操作这个元素(比如选择文本框的文本,改变 select 的 index 等), 普通方式写代码通常不起作用,但是放入 setTimeout( func, 0 ) 中就可以达到效果。

要理解这个问题还是要了解 浏览器的 UI 线程。

单线程的浏览器, js 引擎和渲染引擎必定是顺序执行 (stack),比如点击一个按钮,浏览器会先改变按钮的状态(actived,重绘), 然后才执行 js (js引擎) 。

所以往 dom 插入元素再立刻操作这个 dom ,那么很有可能这个 dom 还没有重绘完成,因此操作无效。

那么,为什么放入 setTimeout( func, 0 ) 中就可以呢? 其实答案已经出来了, setTimeout 会等到重绘完成才执行代码,自然无往而不利。

setTimeout 进一步理解

可以更深入的思考: setTimeout( func, 0 ) 是延迟 0ms 执行,也就是立刻执行,但为什么还是在重绘之后呢? 重绘肯定会超过 0ms 啊!

到这里才是这篇笔记的终极目的, javascript单线程的异步模式。

jQuery 作者 John Resig 的这篇《How JavaScript Timers Work》通俗易懂地阐述了这个问题……

以下是我对这篇文章的理解:


理解 javasript 定时器的内部机制是必要的,虽然有时候这些定时器表现的很古怪。

为了理解定时器的内部机制,有一点必须着重强调:延迟时间的精确度无法保证,比如延迟 10ms ,回调函数不一定在 10ms 后执行。 这是因为,浏览器中的 javascript引擎是单线程,所有的异步函数必须等到适合的时间执行。

为了更好地阐述,John 采用了看图说话的方式,点击查看图片

图中蓝色的圆角矩形是 js 块(javascript block) ,右边的数字表示时间,“问题”是模拟浏览器的判断,左边则是 javascript代码的执行时间。 比如第一个 js 块执行了大概 18ms ,“点击事件”大概执行了 11ms 等等。

既然是单线程,这些 js 块都是互相阻塞的,第一个 js 块执行过程中, "click" 被触发,但是必须排队,等到第一个块执行完才执行(当然, 排队的方式在各浏览器中不同,我们这里不关注这个)。

接下来就好理解了——

开始,在第一个 js 块中,两个延迟 10ms 的 timer 被初始化,注意这个 10ms ,不保证 10ms 后一定执行,两个 timer 必然会是在第一个 js block 执行完之后才执行。

另外,在第一个 js 块中,鼠标点击了,但是事件处理函数不会立刻执行,和 timer 一样,也要等到一个 js block 执行完后才执行。

终于,第一个 js 块执行完。这个时候浏览器会问,接下来干嘛。事件处理函数和 timer 都在等待,于是事件处理函数执行, timer 继续等待。

在事件处理函数执行过程中,10ms 的 interval 触发了,毫无疑问不会立刻执行,进入队列等待。

事件处理函数执行完毕, timer 执行,这个时候, interval 又触发了,要知道上一个 interval 还没有执行,怎么办?

这一次的 interval 会被抛弃 (dropped) 。如果不抛弃,那么有可能大量的 interval 会在 timer 执行完后同时执行,这显然不符合逻辑。 对于这,浏览器的排队方式是先检查有没有 interval ,如果没有,排队,有就抛弃。

继续看,当 timer 执行完, 第一个 interval 执行,在这个过程中,第三个 interval 触发.在其自身执行过程中,自身也可以被触发。 可见, setInterval 不管当前在执行什么,他都会强行排队,即使本身还没执行完。

最后没什么好说的了,没什么可等,所有的 interval 会立刻执行。

再来看看 setTimeout 和 setInterval 之间的区别:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
setTimeout(function(){
    /* Some long block of code... */
    setTimeout(arguments.callee, 10);
}, 10);

setInterval(function(){
    /* Some long block of code... */
}, 10);

乍一看,效果一样,其实区别很大。

setTimeout 总是会在其回调函数执行后延迟 10ms (或者更多,但不可能少),而 setInterval 总是 10ms 执行一次,而不管 它的回调函数执行多久。

总结:

  • javascript引擎是异步的,总是强制异步过程排队。
  • setTimeout 和 setInterval 的机制完全不同。
  • 定时器的代码总是会被延迟到下一个可能的时间点执行,这个时间点很可能比你给定的时间要长。
  • 如果 Intervals 的回调执行时间比你给定的 delay 还要长,那么他们会连在一起执行。

上面就是 John 对 timer 的解释,唯一的缺憾是没有把渲染引擎的执行考虑进去。

setTimeout 中的 this

setTimeout 中的 this 被无数人吐槽过,老道直接说这是语言设计错误。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var o = {
    a: "a",
    b: function() {
        setTimeout(function() {
            console.log( this.a ); 
        }, 1000);
    }
}

o.b();  // undefined

是的,上面的这种情况,setTimeout 的 this 会指向全局作用域,于是 a 是 undefined 。

解决办法很多,最简单的是:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var o = {
    a: "a",
    b: function() {
        var that = this;
        setTimeout(function() {
            console.log( that.a ); 
        }, 1000);
    }
}

o.b();  // "a"
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2015-12-06 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理
前言 见解有限,如有描述不当之处,请帮忙及时指出,如有错误,会及时修正。 超长文+多图预警,需要花费不少时间。 最近发现有不少介绍JS单线程运行机制的文章,但是发现很多都仅仅是介绍某一部分的知识,而且各个地方的说法还不统一,容易造成困惑。 因此准备梳理这块知识点,结合已有的认知,基于网上的大量参考资料, 从浏览器多进程到JS单线程,将JS引擎的运行机制系统的梳理一遍。 展现形式:由于是属于系统梳理型,就没有由浅入深了,而是从头到尾的梳理知识体系, 重点是将关键节点的知识点串联起来,而不是仅仅剖析某一部分知识
用户1097444
2022/06/29
5720
从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理
「Web编程API」- 04
请注意,本文编写于 2088 天前,最后修改于 174 天前,其中某些信息可能已经过时。
曼亚灿
2023/05/17
9160
「Web编程API」- 04
js中settimeout()的用法详解_低噪放工作原理
setTimeout与setInterval是JavaScript引擎提供的两个定时器方法,分别用于函数的延时执行和循环调用。前者的主要思想是通过一个定时器,让函数在计时结束后再执行;后者则是每隔一定的时间,就启动一次函数的执行。
全栈程序员站长
2022/11/09
1.8K0
js中settimeout()的用法详解_低噪放工作原理
你所不知道的setTimeout
JavaScript提供定时执行代码的功能,叫做定时器(timer),主要由setTimeout()和setInterval()这两个函数来完成。它们向任务队列添加定时任务。初始接触它的人都觉得好简单,实时上真的如此么?这里记载下,一路对其使用姿势变迁的历程。 1, setTimeout()基础 setTimeout函数用来指定某个函数或某段代码,在多少毫秒之后执行。它返回一个整数,表示定时器的编号,以后可以用来取消这个定时器。 var timerId = setTimeout(func|code, de
晚晴幽草轩轩主
2018/03/27
1.9K0
setTimeout的那些事
本文介绍了setTimeout函数的基本用法,包括延迟执行、循环执行、指定延迟执行、指定回调函数、取消定时器、定时器ID、封装好的常用工具函数以及实际场景中的应用案例。
IMWeb前端团队
2017/12/28
2.1K0
从setTimeout分析浏览器线程
[toc]   今天接到阿里的面试电话,面试官很和善,聊聊天的形式不知不觉就是一个小时。本人接触前端不深,面试的时候问的几个问题也让我发现自身学习过程中思考太少,其中一个就是问到了setTimeout的工作机理,当时简单讲了讲我自己的想法,面试官也指出了其中的问题,现查阅资料重新整理记录。
csxiaoyao
2019/02/15
1.2K0
从setTimeout分析浏览器线程
详解 JS 中的事件循环、宏/微任务、Primise对象、定时器函数,以及其在工作中的应用和注意事项
当时的我年轻气盛,在简历上放了自己的博客地址,而面试官应该是翻了我的博客,好几道面试题都是围绕着我的博文来提问
用户6256742
2024/06/22
4110
「硬核JS」一次搞懂JS运行机制
从开始做前端到目前为止,陆续看了很多帖子讲JS运行机制,看过不久就忘了,还是自己理一遍好些
isboyjc
2022/03/28
2K0
「硬核JS」一次搞懂JS运行机制
【THE LAST TIME】彻底吃透 JavaScript 执行机制
首先我们需要声明下,JavaScript 的执行和运行是两个不同概念的,执行,一般依赖于环境,比如 node、浏览器、Ringo 等, JavaScript 在不同环境下的执行机制可能并不相同。而今天我们要讨论的 Event Loop 就是 JavaScript 的一种执行方式。所以下文我们还会梳理 node 的执行方式。而运行呢,是指JavaScript 的解析引擎。这是统一的。
Nealyang
2019/09/29
4730
【THE LAST TIME】彻底吃透 JavaScript 执行机制
22道js输出顺序问题,你能做出几道
单线程是 JavaScript 核心特征之一。这意味着,在 JS 中所有任务都需要排队执行,前一个任务结束,才会执行后一个任务。
loveX001
2022/12/14
2K0
为什么要用 setTimeout 模拟 setInterval ?
来源:九旬 https://segmentfault.com/a/1190000038829248
@超人
2021/02/26
1.2K0
为什么要用 setTimeout 模拟 setInterval ?
为什么要用 setTimeout 模拟 setInterval ?
在[JS 事件循环之宏任务和微任务](../Performance/JS事件循环之宏任务和微任务.html)中讲到过,setInterval 是一个宏任务。
九旬
2021/01/06
1.2K0
深入理解Javascript单线程谈Event Loop
假如面试回答js的运行机制时,你可能说出这么一段话:“Javascript的事件分同步任务和异步任务,遇到同步任务就放在执行栈中执行,而碰到异步任务就放到任务队列之中,等到执行栈执行完毕之后再去执行任务队列之中的事件。”但你能说出背后的原因吗?
小周sir
2019/09/23
1.6K0
深入理解Javascript单线程谈Event Loop
JavaScript设置定时器、取消定时器及执行机制解析
今天整理了一下 JavaScript 定时器,顺便了解了一下 JavaScript 的运行机制,现在记录一下。
德顺
2019/11/12
5K0
JavaScript中定时器的工作原理(How JavaScript Timers Work)
原文链接:https://johnresig.com/blog/how-javascript-timers-work/
德顺
2020/03/05
1.5K0
JavaScript中定时器的工作原理(How JavaScript Timers Work)
你不知道的 Event Loop
笔者最近忙着做项目之类的,文章输出遗落下了一段时间,这次我们就来聊一个面试中一个比较重要的知识点 —— Event Loop
一只图雀
2020/04/07
8870
前端成神之路-WebAPIs04
​ BOM(Browser Object Model)即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是 window。
海仔
2020/12/29
1.5K0
setTimeout和requestAnimationFrame
JavaScript语言的一大特点就是单线程,也就是说,同一时间只能做一件事,前面的任务没做完,后面的任务只能等着。
木子星兮
2020/07/16
1.8K0
深度解密setTimeout和setInterval——为setInterval正名!
重复定时器,JS有一个方法叫做setInterval专门为此而生,但是大家diss他的理由很多,比如跳帧,比如容易内存泄漏,是个没人爱的孩子。而且setTimeout完全可以通过自身迭代实现重复定时的效果,因此setIntervval更加无人问津,而且对他退避三舍,感觉用setInterval就很low。But!setInverval真的不如setTimeout吗?请大家跟着笔者一起来一步步探索吧!
小美娜娜
2019/04/04
4K0
深度解密setTimeout和setInterval——为setInterval正名!
# JavaScript 专题之 This 和定时器
思维导图:https://naotu.baidu.com/file/7d05ddb397c649f62136040993cbd04bopen in new window
九旬
2023/10/18
1810
# JavaScript 专题之 This 和定时器
相关推荐
从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验