前言:问题引出

  JavaScript中会经常用到setTimeout来推迟一个函数的执行,如:

 setTimeout(function(){alert("Hello World");},1000)

  它的意思是会在执行到这句话后延迟1秒钟(1000毫秒)来弹出alert窗口。

  那么再看这一段:

 function a() {
setTimeout(function() {alert(1)}, 0);
alert(2);
}

  注意,这段代码中的setTimeout延迟设为了0,就是延迟0毫秒,貌似是不做任何延迟立刻执行。但实际的执行结果确是先弹出2再弹出1,这是为什么呢?JavaScript API文档明确定义第二个参数意义为隔多少毫秒后,回调方法就会被执行。这里设成0毫秒,理所当然就立即被执行了!?这得从Javascript调用堆栈(call stack)和setTimeout的功能说起。

问题剖析

  首先,JavaScript引擎是单线程运行的,浏览器无论在什么时候都有且只有一个线程在运行JavaScript程序,即同一时间只执行一条代码,所以每一个JavaScript代码执行块会“阻塞”其它异步事件的执行。

  其次,和其他的编程语言一样,Javascript中的函数调用也是通过堆栈实现的。如上例中,在执行函数a的时候,函数a先入栈,如果不给alert(1)加setTimeout,那么alert(1)第2个入栈,最后是alert(2)。但现在给alert(1)加上setTimeout后,alert(1)就被加入到了一个新的堆栈中等待,并“尽可能快”的执行。这个尽可能快就是指在a的堆栈完成后就立刻执行,因此实际的执行结果就是先alert(2),再alert(1)。在这里setTimeout实际上是让alert(1)脱离了当前函数调用堆栈。

扩展:AJAX是否真的异步?

  既然说JavaScript是单线程运行的,那么XMLHttpRequest在连接后是否真的异步?

  其实请求确实是异步的,不过这请求是由浏览器新开一个线程请求,当请求的状态变更时,如果先前已设置回调,这异步线程就产生状态变更事件放到 JavaScript引擎的处理队列中等待处理,当任务被处理时,JavaScript引擎始终是单线程运行回调函数,具体点即还是单线程运行onreadystatechange所设置的函数。

扩展:setTimeout的 应用场景

一、解决双击事件触发单击事件的冲突

  提示:默认双击会先触发单击事件,使用延迟单击事件进行处理。

 function click(){
  isdb=false;
  window.setTimeout(cc, 500)
  function cc(){
    if(isdb!=false)return;
    alert("单击")
  }
}
function dblclick(){
  isdb=true;
  alert("双击")
}

二、解决双击事件触发单击事件的冲突

  AJAX请求后台,调用webservice或调用大量数据查询等情况造成前台一直处于loading加载框的情况,可以使用setTimeout来解决。

  部分JQ源码如下:

 if ( s.async && s.timeout > 0 ) {
timeoutTimer = setTimeout(function() {
jqXHR.abort("timeout");
}, s.timeout );
}

编后语

  本博文简单介绍了setTimeout和JS单线程的知识,这块水其实很深,但这边只做一个随笔。有兴趣的同学,推荐阅读jQuery作者John的一篇文章:How JavaScript Timers Work,你会对JavaScript单线程本质和setTimeout以及setInterval有更加深刻的理解。

  http://ejohn.org/blog/how-javascript-timers-work/

  当你理解了JS的单线程和堆栈原理,那在使用JS进行高级程序编写中,必然会得心应手。

  当你还在说JavaScript是一门玩具型的脚本语言时,它也在远处嘲笑你对它不够了解。

  

《无所不能的JavaScript编程系列:setTimeout 简笔》的更多相关文章

  1. 简单物联网:外网访问内网路由器下树莓派Flask服务器

    最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...

  2. 利用ssh反向代理以及autossh实现从外网连接内网服务器

    前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...

  3. 外网访问内网Docker容器

    外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...

  4. 外网访问内网SpringBoot

    外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...

  5. 外网访问内网Elasticsearch WEB

    外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...

  6. 怎样从外网访问内网Rails

    外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...

  7. 怎样从外网访问内网Memcached数据库

    外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...

  8. 怎样从外网访问内网CouchDB数据库

    外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...

  9. 怎样从外网访问内网DB2数据库

    外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...

  10. 怎样从外网访问内网OpenLDAP数据库

    外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...

随机推荐

  1. Java 如何启用 ARM 虚拟机诊断

    现象描述 如何通过 Java 语言实现在创建 ARM 虚拟机时开启诊断,并配置相关指标.   实现思路 调研最高版本的 JAVA SDK(1.1.0)源码发现,SDK 层面并未提供任启动诊断和配置诊断 ...

  2. 关于npm run build打包后css样式中的图片失效的问题(如background)

    平时run dev都能正常显示的css背景图片在npm run build打包后竟然不显示了(写在标签对中的图片都可以正常显示),而且dist/static/img目录下是确实有这张图片的,于是查看打 ...

  3. Visual Studio 2012自动添加注释(如版权信息等)

    转自:http://blog.163.com/guohuan88328@126/blog/static/69430778201381553150156/ 如何使用Visual Studio 2012给 ...

  4. centos 7 linux x64

    1.修改软件源 sudo wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo yum updat ...

  5. Linux磁盘空间占满问题快速定位

    1.df -h命令查看系统盘与各个磁盘的占用空间比率 [tidb@:vg_adn_tidbCkhsTest:172.31.30.62 /dev]$df -Th Filesystem Type Size ...

  6. IDEA中的替换功能(替换代码中的变量名很好用哦)

    刚刚上班不久,这两天正在研究公司项目里面的代码,今天用阿里的插件扫描了一下代码,发现代码中有很多变量的命名,没有遵循驼峰式的命名规则.一开始我一个一个的修改这些变量名,后来无意中用了一下Ctrl+F( ...

  7. SDN 第四次上机作业

    1.建立以下拓扑,并连接上ODL控制器. 2.利用ODL下发流表,使得h3在10s内ping不通h1,10s后恢复. 3.借助Postman通过ODL的北向接口下发流表,再利用ODL北向接口查看已下发 ...

  8. 闲谈CDN网络架构

    CDN也就是内容分布网络(Context Delivery Network),它是构筑在现有interent上的一种先进的流量分配网络.其目的是通过现有的Internet中增加一层新的网络架构,将网站 ...

  9. Win8下IIS的安装和站点的公布

    版权声明:本文为博主原创文章,不经博主同意注明链接就可以转载. https://blog.csdn.net/Senior_lee/article/details/32939411         之前 ...

  10. Odoo进销存业务思路浅析

    转载请注明原文地址:https://www.cnblogs.com/cnodoo/p/9307485.html  一:采购业务(进) 1:根据采购对象和性质,采购业务主要分为四类: 生产性采购:采购企 ...