Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,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 删除。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
ios的邮箱怎么用_ios邮箱怎么添加多个账号
#import <MessageUI/MFMailComposeViewController.h>
全栈程序员站长
2022/11/08
1.3K0
iOS发送短信的代码
#pragma mark -发送短信 @interface ViewController () { UIAlertView *mfAlertview;//定义一个弹出框 } -(void)showMessageViewController { if( [MFMessageComposeViewController canSendText] )//判断是否能发短息 { MFMessageComposeViewContr
大师级码师
2021/09/19
4.1K0
IOS中调用系统拨打电话与发送短信 原
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"tel://%@",_phoneNumber]]];
珲少
2018/08/15
5360
iOS应用内发送邮件
iPhone API已经提供了系统写邮件界面的接口,使用MFMailComposeViewController,用来显示界面. 项目中需要添加MessageUi.framework。头文件加入MFMailComposeViewControllerDelegate。#import <MessageUI/MessageUI.h> sendMailViewController.m文件的实现: (void)viewDidLoad { UIButton *button = [UIButton butto
用户8671053
2021/10/31
8020
iOS应用发送SMS短消息代码
//Import the MessageUI Framework into your project and //#import the header file into the “.h” file of your controller //where you want to open the In-App SMS sheet. -(IBAction) sendInAppSMS:(id) sender { MFMessageComposeViewController *controller =
用户8671053
2021/10/31
7530
iOS开发之调用系统打电话发短信接口以及程序内发短信
  在本篇博客开头呢,先说一下写本篇的博客的原因吧。目前在做一个小项目,要用到在本应用程序内发验证码给其他用户,怎么在应用内发送短信的具体细节想不大起来了,于是就百度了一下,发现也有关于这方面的博客,点进去看了看,个人感到有点小失望,写的太不详细,只是简单的代码罗列,而且代码也没注释,大概是因为太简单了吧。今天在做完项目的发短信功能后感觉有必要把这部分内容整理一下,做个纪念也是好的不是吗。废话少说,切入今天的正题。下面的发短信,打电话当然需要真机测试了。   一、调用系统功能     在iOS中打开系统本身
lizelu
2018/01/11
13K0
iOS开发之调用系统打电话发短信接口以及程序内发短信
UIActivityViewController系统原生分享-仿简书分享
利用UIActivityViewController实现系统原生分享,不需要三方SDK,支持自定义分享,可以分享到微博、微信、QQ、信息、邮件、备忘录、通讯录、剪贴板、FaceBook.....等等
且行且珍惜_iOS
2018/05/22
3.7K0
iOS发送邮件的代码
3.实现代理<MFMailComposeViewControllerDelegate> 和 <UINavigationControllerDelegate>
艳艳代码杂货店
2021/10/29
6620
调用 MFMessageComposeViewController UINavigationBar 高出一截
项目告一段落,总结一下项目中遇到的坑 使用 MFMessageComposeViewController 在程序内部发送短信,代码很简单 MFMessageComposeViewController * controller = [[MFMessageComposeViewController alloc] init]; controller.recipients = @[收件人手机号码1,收件人手机号码2,收件人手机号码3]; controller.body = 短信内容 controller.mess
GuangdongQi
2018/05/24
5790
android 短信验证码的实现
进入后在上面有应用是让选择android还是ios 之类的,点击下载SDK –选择免费短信验证SDK,
全栈程序员站长
2022/09/16
2.8K0
android 短信验证码的实现
基础篇-应用之间的跳转
在应用A跳转到应用B,则给A、B自身自定义URL Schemes(自定义的协议头)后,通过在A中处理B的URL Schemes,就可以在A中启动B了。
進无尽
2018/09/12
9040
基础篇-应用之间的跳转
Android极速开发之发送短信
实现SMS主要用到SmsManager类,该类继承自java.lang.Object类,下面我们介绍一下该类的主要成员。
Javen
2018/08/21
2.3K0
iOS_调起各个地图软件
#pragma mark - 弹出选择地图alert + (void)popMapsAlertWithVC:(UIViewController *)vc toCoor:(CLLocationCoordinate2D)toCoor targetName:(NSString *)targetName { NSArray *mapSchemeArr = @[@"iosamap://", @"baidumap://", @"qqmap://", @"comgooglemaps://"]; NSArray *
mikimo
2022/07/20
3640
C# 实现发送手机短信
现在很多网站都是短信发送的功能,怎么实现的呢。对于个人站长来说的话,通过使用SMS短信通API接口相对比较划算和简单。那怎么实现呢,步骤如下: 1. 从网上(http://sms.webchinese
逸鹏
2018/04/09
4.8K0
C# 实现发送手机短信
java批量发送短信设计防止重复发送
在开发短信发送功能时,防止重复发送是一个关键问题。重复发送可能导致用户接收到多条相同的短信,影响用户体验和成本控制。
用户1098398
2024/07/05
3750
客户端是移动端吗_谈单的技巧
1、只要申请了百度开发账号,创建了工程,就不需要在新浪微博、腾讯微博、人人网等开放平台中申请应用,好处显而易见,不用再去各个平台申请加审核了,坏处是授权的时候显示的不是授权给应用的名字,而是授权给百度社会化分享;
全栈程序员站长
2022/11/09
8130
iOS开发之诱导用户为自己的App评论功能
allluckly.cn.jpg "由于我自己的App下载量少,评论也少,出于App的aso优化,想尽办法,而评论是aso里边比较重视的一块,前面的版本都没有诱导用户评论的这一功能,导致有些被动。" 由此自己简单的封装了该功能,下面我们先看看效果图: 1.png 弹出试图并没有做什么处理,就是系统的8.0以前用的UIAlertView8.0以上用的UIAlertController 具体的一些算法,都可以看代码,闲话不多说,直接贴码, 新建一个NSObject的类命名为LBToAppStore 具
Bison
2018/07/04
1K0
iOS-UIApplication详解iOS-UIApplication详解
iOS-UIApplication详解 ✨建议收藏,用到时候一查就明白了 xx_cc UIApplication简介 UIApplication对象是应用程序的象征。 每一个应用程序都有自己的UIApplication对象,而且是单例。 一个iOS程序启动后创建的第一个对象就是UIApplication对象。 通过UIApplication *app = [UIApplication sharedApplication];可以获得这个单例对象。 利用UIApplication对象能进行一些应用级别的操作。
xx_Cc
2018/05/10
1.7K0
iOS摄像头和相册-UIImagePickerController
本文参考自:http://blog.sina.com.cn/s/blog_7b9d64af0101cfd9.html
Cloudox
2021/11/23
8400
iOS应用调用系统打电话、发短信和发邮件功能引1、打电话2、发短信3、发邮件
在应用程序内,调用系统的功能来实现打电话、发短信和发邮件,通过电话号码或者邮箱,直接跳转到系统的功能界面。
Cloudox
2021/11/23
4K0
相关推荐
ios的邮箱怎么用_ios邮箱怎么添加多个账号
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验