前言:问题引出

  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. python基础知识回顾之元组

    元组与列表的方法基本一样,只不过创建元组是用小括号()把元素括起来,两者的区别在于,元组的元素不可被修改. 元组被称为只读列表,即数据可以被查询,但不能被修改,列表的切片操作适用于元组. 元组写在小括 ...

  2. Finding the source of signals on Linux with strace, auditd, or systemtap

    inux and UNIX® like operating systems commonly use signals to communicate between processes. The use ...

  3. 《SQL Server 2008从入门到精通》--20180716

    1.锁 当多个用户同时对同一个数据进行修改时会产生并发问题,使用事务就可以解决这个问题.但是为了防止其他用户修改另一个还没完成的事务中的数据,就需要在事务中用到锁. SQL Server 2008提供 ...

  4. db2错误代码大全

    ---恢复内容开始--- sqlcode sqlstate 说明000 00000 SQL语句成功完成01xxx SQL语句成功完成,但是有警告+012 01545 未限定的列名被解释为一个有相互关系 ...

  5. java中的String类的不可变性的小例子

    在java语言中,String类具有不可变性,即常量字符串不可更改.下面的一个小例子简单演示相关概念. public class test { public static void main(Stri ...

  6. Redis雪崩、穿透、热点key等优化

    一.缓存 Redis做缓存是最常见的应用场景.客户端请求在缓存层命中就直接返回,如果miss就去读取存储层,存储层读取到就写入缓存层,然后再返回到客户端. 优点: 加速读写 降低后端负载 缺点: 数据 ...

  7. pt-table-checksum工具MySQL主从复制数据一致性

    所使用的工具是pt-table-checksum 原理是: 在主上执行检查语句去检查 mysql主从复制的一致性,生成 replace 语句,然后通过复制传递到从库,再通过update 更新 mast ...

  8. xml的xsi:type序列化和反序列化

    最近在做HL7V3的对接,关于XML的序列化和反序列化遇到xsi:type的问题解决方法 实体类定义: public class HL7V3_ProviderOrganization { public ...

  9. 第 14 章 结构和其他数据形式(names)

    *--------------------------------- names1.c -- 使用指向结构的指针 ---------------------------------*/ #includ ...

  10. SDN 第二次上机作业

    SDN第二次上机作业 1.控制器floodlight所示可视化图形拓扑的截图,及主机拓扑连通性检测截图 拓扑 连通性 2.利用字符界面下发流表,使得'h1'和'h2' ping 不通 流表截图 连通性 ...