《无所不能的JavaScript编程系列:setTimeout 简笔》
前言:问题引出
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 简笔》的更多相关文章
- 简单物联网:外网访问内网路由器下树莓派Flask服务器
最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...
- 利用ssh反向代理以及autossh实现从外网连接内网服务器
前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...
- 外网访问内网Docker容器
外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...
- 外网访问内网SpringBoot
外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...
- 外网访问内网Elasticsearch WEB
外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...
- 怎样从外网访问内网Rails
外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...
- 怎样从外网访问内网Memcached数据库
外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...
- 怎样从外网访问内网CouchDB数据库
外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...
- 怎样从外网访问内网DB2数据库
外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...
- 怎样从外网访问内网OpenLDAP数据库
外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...
随机推荐
- 【转】Java学习—什么是时间复杂度
[原文]https://www.toutiao.com/i6593144782992704007/ 转载:程序员小灰 时间复杂度的意义 究竟什么是时间复杂度呢?让我们来想象一个场景: 某一天,小灰和大 ...
- 自己动手制作一个本地的yum仓库
制作本地yum源有两种方式,第一种是使用光盘镜像,然后在本地进行安装.第二种是我们自己创建一个本地yum仓库,然后使用file的形式来向本地提供yum repo(也可以使用http的方式向外部提供,我 ...
- 【12】python 栈型数据结构模拟、队列型数据结构模拟
一.压栈操作模拟 #__author:"吉*佳" #date: 2018/10/21 0021 #function:栈 # 栈:即是先进后出的一种数据结构 # (1)模拟压栈操作 ...
- 【Alpha 冲刺】 9/12
今日任务总结 人员 今日原定任务 完成情况 遇到问题 贡献值 胡武成 完善API文档,并初步使用SpringMVC产生编写部分API 已完成 孙浩楷 完成课程通知页面(及发布通知的弹窗) 已完成 胡冰 ...
- 团队作业——Alpha冲刺2/12
团队作业--Alpha冲刺 冲刺任务安排 杨光海天 今日任务:主要学习JAVA语言,以及加入了Android开发内容的学习. 明日任务:安装Android Studio以及通过观看视频和阅读材料的形式 ...
- 3.Solr4.10.3目录结构
转载请出自出处:http://www.cnblogs.com/hd3013779515/ 1.整个目录结构 (1)bin:是脚本的启动目录 (2)contrib:第三方包存放的目录 (3)dist:编 ...
- git版本管理工具-git的概述
什么是git Git是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目的一种工具 Git 与常用的版本控制工具 CVS, Subversion 等不同,它采用了分布式版本库的方式,不 ...
- 2.HBase In Action 第一章-HBase简介(1.1数据管理系统:快速学习)
Relational database systems have been around for a few decades and have been hugely successful in so ...
- Linux版的Mimikaz
A tool to dump the login password from the current linux desktop user. Adapted from the idea behind ...
- FileUriExposedException_Android7.0适配
一. FileUriExposedException的解决 问题 由于在Android7.0上,google使用了新的权限机制,所以导致在调用相机的时候,如果传递的URI为”file://”类型,的系 ...