原来你是这样的setTimeout
先上代码
console.log("start");
setTimeout(function(){
console.log("Hello");
},200);
setTimeout(function(){
console.log("World");
},100);
console.log("end");
start
end
undefined
World
Hello
如果看出了结果,那么我们修改一下代码
console.log("start");
setTimeout(function(){
console.log("Hello");
},200);
setTimeout(function(){
console.log("World");
},300);
for(var i = 0;i <= 1000; i++){
console.log(i);
}
setTimeout(function(){
console.log("I am here!");
},100);
console.log("end");
start
end
undefined
I am here!
Hello
World
是的,在我们看来这是正确的,没有错误的。
那我们再稍微修改一下我们的代码
console.log("start");
setTimeout(function(){
console.log("Hello");
},200);
setTimeout(function(){
console.log("World");
},300);
for(var i = 0;i <= 10000; i++){
console.log(i);
}
setTimeout(function(){
console.log("I am here!");
},100);
console.log("end");
start
end
undefined
Hello
World
I am here!
是不是很神奇。首先得从JS引擎说起。
JS引擎在内存中会分配堆区和栈区。
我们来看一段代码
function A(){
var a = 4;
b(a);
}
function B(num){
var newNum = num * num;
console.log(newNum);
}
A();
步骤:运行A()方法,将A()入栈。A上下文中存在变量a = 4
调用B()方法,将B()入栈。B上下文中存在变量num = 4,newNum = 16
调用B()方法中的console.log(),入栈,打印出16.
继续运行,将console.log()、B()方法,出栈,A()方法运行完毕出栈,代码运行完毕,清空栈。
众所周知,JS引擎是单线程的,在某一个特定时间只能执行一个任务,并阻塞其他任务的执行,也就是说这些任务是串行的。用户不得不等待一个耗时的操作完成之后才能继续后面的操作,实际开发中我们可以使用异步代码来解决问题。
EventLoop事件循环
当异步方法比如这里的setTimeout(),或者Ajax请求、DOM事件执行的时候,会交由浏览器内核的其他模块去管理。当异步的方法满足触发条件之后,该模块就将方法推入到一个任务队列(task queue)中,当主线程代码执行完毕处于空闲状态的时候,就会检查任务队列,将队列中的第一个任务入栈执行,完毕后继续检查任务队列,如此循环。
前提条件:主线程处于空闲状态,这就是事件循环的模型。
我们来看一下第一个列子:
首先console.log()入栈,打印完毕之后出栈,紧接着执行到setTImeout()计时器,此时JS引擎会将定时器交给浏览器的另一个模块去管理,在这里我们称Timer()模块,紧接着第二个计时器也交给Timer模块。
然后执行到第二个console.log(),执行完毕后清空执行栈。
但是并没有结束,在主线程执行的同时,Timer()模块会检查其中的代码,一旦满足触发条件,就会将它添加到任务队列中,TImer2延迟100秒,所以在于Timer1被添加到队列开头。而主线程此时处于空闲状态,所以会检查任务队列是否有待执行的任务。
此时会将队列中的Timer2()执行,控制台打印,然后执行栈清空,继续检查任务队列,将Timer1()入栈并执行,控制台打印,清空执行栈。此时任务队列为空,清空执行栈。
然后我们来看第二段和第三段代码,就比较好玩了
和第一段不同的是,在最后一个定时器前加了一个for循环,我们模拟了一个1000和10000的for循环。
第三段比较奇怪。Timer3仅仅延迟了100毫秒,反而在两个Timer()之后执行了。
想想看,为什么?
原因很简单,因为在Timer1和Timer2加入到执行队列中后,主线程仍然执行着for循环中的代码,处于阻塞状态。队列中的Timer1和Timer2并不会得以执行。
当for循环结束,这时才将Timer3交由Timer模块去管理,继续执行后续代码打印"end",清空执行栈。虽然Timer3的延迟时间很短,但是加入任务队列后还是会排在Timer1和Timer2的后面,所以此时会按顺序执行任务队列中的代码。同时需要注意的是,这种情况下的三个定时器延迟执行的时间已经远远超过了指定的时间。
总结:我们发现不论事件循环模型还是setTimeout机制,其实不是难点,但却是容易忽略的点。很多问题的产生是因为忽略了一些简单的原理导致的。
原来你是这样的setTimeout的更多相关文章
- setTimeout 的黑魔法
setTimeout,前端工程师必定会打交道的一个函数.它看上去非常的简单,朴实.有着一个很不平凡的名字--定时器.让年少的我天真的以为自己可以操纵未来.却不知朴实之中隐含着惊天大密.我还记得我第一次 ...
- 你所不知道的setTimeout
JavaScript提供定时执行代码的功能,叫做定时器(timer),主要由setTimeout()和setInterval()这两个函数来完成.它们向任务队列添加定时任务.初始接触它的人都觉得好简单 ...
- setTimeout那些事儿
一.setTimeout那些事儿之单线程 一直以来,大家都在说Javascript是单线程,浏览器无论在什么时候,都且只有一个线程在运行JavaScript程序. 但是,不知道大家有疑问没——就是我们 ...
- 深入理解定时器系列第一篇——理解setTimeout和setInterval
× 目录 [1]setTimeout [2]setInterval [3]运行机制[4]作用[5]应用 前面的话 很长时间以来,定时器一直是javascript动画的核心技术.但是,关于定时器,人们通 ...
- 前端开发:setTimeout与setInterval 定时器与异步循环数组
前端开发:setTimeout与setInterval 定时器与异步循环数组 前言: 开通博客园三个月以来,随笔记录了工作中遇到的大大小小的难题,也看过无数篇令人启发的文章,我觉得这样的环境是极好的, ...
- javascript函数setInterval和setTimeout的使用区别详解
setTimeout和setInterval的使用 这两个方法都可以用来实现在一个固定时间段之后去执行JavaScript.不过两者各有各的应用场景. 方 法 实际上,setTimeout和setIn ...
- UNITY实现FLASH中的setTimeout
setTimeout是一个很方便的DELAY处理方法 if (this.startUpDelay > 0){ StartCoroutine(DelayedStart()); ...
- setTimeout和setInterval从入门到精通
我们在日常web前端开发中,经常需要用到定时器方法. 前端中的定时器方法是浏览器提供的,并不是ECMAScript规范中的.是window对象的方法. 浏览器中的定时器有两种, 一种是每间隔一定时间执 ...
- setTimeout和setInterval定时器使用详解测试
var len=4; while(len--){ var time=setTimeout(function(){ console.log(len); },0); console.log(time); ...
- setTimeout 和 throttle 那些事儿
document.querySelector('#settimeout').onclick= function () { setTimeout(function () { console.log('t ...
随机推荐
- GDAL——命令使用专题——gdalsrsinfo命令
GDAL——命令使用专题——gdalsrsinfo命令 前言 GDAL(Geospatial Data Abstraction Library)是一个在X/MIT许可协议下的开源栅格空间数据转换库. ...
- fatal error C1010: 在查找预编译头时遇到意外的文件结尾
错误描述:fatal error C1010: 在查找预编译头时遇到意外的文件结尾.是否忘记了向源中添加“#include "stdafx.h"”? 错误分析: 此错误发生 ...
- 程序员必会算法-KMP算法
KMP算法是一种优秀的字符串匹配算法,字符串匹配的常规算法是一步一步进行移位和比较操作,直至找到完全相匹配的字符串. 下面通过一个例子,为大家仔细说明KMP算法的使用和思路: 问题: 在字符串“DEA ...
- [NOIP2014D2]
T1 Problem 洛谷 Solution 枚举那个点的位置,再O(n)扫一遍求出覆盖的公共场合的数量... 所以时间复杂度为O(128 * 128 * n) Code #include<cm ...
- 20190219备份 java spring boot 学习链接(日/英)
Building web applications with Spring Boot and Kotlin https://www.slideshare.net/masuda220/spring-82 ...
- 剖析一个用C++写的行情交易系统
最近hen ci hen ci用C++写完了一整套证券行情系统,但是不是服务沪深交易所的,是给文交所用的.整个系统涵盖了从DBF文件解析开始到客户端展现这一整条逻辑.想来一年多没有更新博客了,所以趁这 ...
- Oracle入门之表结构的管理
建表的基本语法: create table table_name( field1 datatype, field1 datatype, field1 datatype, ... ) 注:table_n ...
- 微信机器人 返现机器人 pc版本 移动版本 java开发 小范省钱
微信机器人 返现机器人 pc版本 移动版本 java开发 小范省钱 微信搜索微信号 fanli-x 或 扫描下方二维码,可查看效果. 非web版微信,pc/移动版微信 支持新号24小时 不封号! 有任 ...
- SharePoint Framework 在web部件中使用第三方样式 - 将第三方样式打到包中
博客地址:http://blog.csdn.net/FoxDave 有许多第三方库可以帮助我们构建丰富的SharePoint Framework客户端web部件.并且这些JavaScript脚本常常包 ...
- MNIST机器学习进阶
# -*- coding: utf-8 -*-"""Created on Wed Oct 17 08:49:28 2018 @author: Administrator& ...