从setTimeout谈js运行机制
众所周知,JavaScript是单线程的编程,什么是单线程,就是说同一时间JavaScript只能执行一段代码,如果这段代码要执行很长时间,那么之后的代码只能尽情地等待它执行完才能有机会执行,不像人一样,人是多线程的,所以你可以一边观看某岛国动作片,一边尽情挥洒汗水。JavaScript单线程机制也是迫不得已,假设有多个线程,同时修改某个dom元素,那么到底是听哪个线程的呢?
既然已经明确JavaScript是单线程的语言,于是我们想方设法要想出JavaScript的异步方案也就可以理解了。比如执行到某段代码,需求是1000ms后调用方法A,JavaScript没有sleep函数能挂起线程一秒啊?如何能够使得代码做到一边等待A方法执行,一边继续执行下面的代码,仿佛开了两个线程一般?机制的科学家们想出了setTimeout方法。
setTimeout方法想必大家都已经很熟悉了,那么setTimeout(function(){..}, a)真的是ams后执行对应的回调吗?
setTimeout(function() {
console.log('hello world');
}, 1000);
while(true) {};
1s中之后,控制台并没有像预料中的一样输出字符串,而网页标签上的圈圈一直转啊转,掐指一算,可能陷入while(true){}的死循环中了,可是为什么呢?虽然会陷入死循环可是也得先输出字符串啊!这就要扯到JavaScript运行机制了。
1.javascript运行机制
一段JavaScript代码到底是如何执行的?阮一峰老师有篇不错的文章(JavaScript 运行机制详解:再谈Event Loop),我就不再重复造轮子了;如果觉得太长不看的话,我在这里简短地描述下。一段js代码(里面可能包含一些setTimeout、鼠标点击、ajax等事件),从上到下开始执行,遇到setTimeout、鼠标点击等事件,异步执行它们,也就是将他们放到任务队列中,此时并不会影响代码主体继续往下执行(当线程中没有执行任何同步代码的前提下才会执行异步代码),一旦异步事件执行完,回调函数返回,将它们按次序加到执行队列中,这时要注意了,如果主体代码没有执行完的话,是永远也不会触发callback的,这也就是上面的一段代码导致浏览器假死的原因(主体代码中的while(true){}还没执行完)。
所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
具体来说,异步执行的运行机制如下。(同步执行也是如此,因为它可以被视为没有异步任务的异步执行。)
(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
(4)主线程不断重复上面的第三步。
"任务队列"是一个事件的队列(也可以理解成消息的队列),IO设备完成一项任务,就在"任务队列"中添加一个事件,表示相关的异步任务可以进入"执行栈"了。主线程读取"任务队列",就是读取里面有哪些事件。
"任务队列"中的事件,除了IO设备的事件以外,还包括一些用户产生的事件(比如鼠标点击、页面滚动等等)。只要指定过回调函数,这些事件发生时就会进入"任务队列",等待主线程读取。
2.setTimeout VS setInterval
根据前文描述,我们大概懂了以上setInterval回调函数的执行时间差<=10ms,因为可能会由于线程阻塞,使得一系列的回调全部在排队。用setTimeout实现的setInterval效果呢?

// 1
function func() {
setTimeout(function() {
// some code
func();
}, 10);
} func(); // 2
setTimeout(function() {
// some code
setTimeout(arguments.callee, 1000);
}, 10);

很显然两个回调之间的间隔是>10ms的,因为前面一个回调在队列中排队,如果没有等到,是不会执行下面的回调的,而>10ms是因为回调中的代码也要执行时间。换句话说,setInterval的回调是并列的,前一个回调(有没有执行)并不会影响后一个回调(插入队列),而setTimeout之间的回调是嵌套的,后一个回调是前一个回调的回调,只有前一个回调执行了,才会把下一个setTimeout事件加入到任务队列。
具体的实现请参见我之前写的《用setTimeout实现setInterval》
从setTimeout谈js运行机制的更多相关文章
- 如何通过setTimeout理解JS运行机制详解
setTimeout()函数:用来指定某个函数或某段代码在多少毫秒之后执行.它返回一个整数,表示定时器timer的编号,可以用来取消该定时器. 例子 ? 1 2 3 4 5 console.log(1 ...
- 从setTimeout谈JavaScript运行机制
从setTimeout说起 众所周知,JavaScript是单线程的编程,什么是单线程,就是说同一时间JavaScript只能执行一段代码,如果这段代码要执行很长时间,那么之后的代码只能尽情地等待它执 ...
- 浅谈js运行机制
前言 因为js的运行机制十分重要,理解起来也十分抽象,仍还是在这里做个记录,加深自己的记忆. 总之,希望本文的内容能够对您的学习或者工作有所帮助.另,如果有任何的错误或者不足请指正! 如何理解js单线 ...
- 从浏览器多进程到JS单线程,JS运行机制的一次系统梳理
前言 见解有限,如有描述不当之处,请帮忙及时指出,如有错误,会及时修正. ----------超长文+多图预警,需要花费不少时间.---------- 如果看完本文后,还对进程线程傻傻分不清,不清楚浏 ...
- 从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理
前言 来源:https://dailc.github.io/2018/01/21/js_singlethread_eventloop.html 见解有限,如有描述不当之处,请帮忙及时指出,如有错误,会 ...
- js 运行机制
<script> console.log(1) setTimeout(function(){ console.log(3) },0) console.log(2) </script& ...
- Js 运行机制 (重点!!)
一.引子 本文介绍JavaScript运行机制,这一部分比较抽象,我们先从一道面试题入手: 这一题看似很简单,但如果你不了解JavaScript运行机制,很容易就答错了.题目的答案是依次输出1 2 3 ...
- Js 运行机制 event loop
Js - 运行机制 (Even Loop) Javascript 的单线程 - 引用思否的说法: JavaScript的一个语言特性(也是这门语言的核心)就是单线程.什么是单线程呢?简单地说就是同一时 ...
- js 运行机制简单了解
一.如何理解 JS 的单线程? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊. JavaScrip ...
随机推荐
- 原创:MVC 5 实例教程(MvcMovieStore 新概念版:mvc5.0,EF6.01) - 4、创建数据上下文和数据实体模型
说明:MvcMovieStore项目已经发布上线,想了解最新版本功能请登录 MVC影视(MvcMovie.cn) 进行查阅.如需转载,请注明出处:http://www.cnblogs.com/Dodu ...
- Javascript设计模式理论与实战:单例模式
在Javascript中,单例模式是一种最基本又经常用到的设计模式,可能在不经意间就用到了单例模式. 本文将从最基础的理论开始,讲述单例模式的基本概念和实现,最后用一个例子来讲述单例模式的应用. 理论 ...
- 在linux中使用包管理器安装node.js
网上文章中,在linux下安装node.js都是使用源码编译,其实node的github上已经提供了各个系统下使用各自的包管理器(package manager)安装node.js的方法. 1. 在U ...
- 配置ssh使用socks代理
ssh -o ProxyCommand='nc -x 127.0.0.1:1080 %h %p' username@server
- 操作XDocument讲解
1.首先建立好XML .可以通选自定义EXCEL导出XML格式的数据:(如图) 2 读取XML 文件 具体的详细讲解 可以查看 改网址 :https://blog.csdn.net/dyllove98 ...
- .net core 2.0 mvc 初步学习
mvc_study *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !impor ...
- 字节码执行方式--解释执行和JIT
此文已由作者赵计刚薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 1.两种执行方式: 解释执行(运行期解释字节码并执行) 强制使用该模式:-Xint 编译为机器码执行(将字 ...
- JVM垃圾收集器(2)
此文已由作者赵计刚薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 1.G1 说明: 从上图来看,G1与CMS相比,仅在最后的"筛选回收"部分不同(CMS ...
- unix网络编程卷2:进程间通信
管道没有名字,只能有亲缘关系使用. FIFO也叫有名管道,有名所以没有了这个限制. 管道提供一个单向数据流,创建函数返回两个文件描述符.一个用来读,一个用来写. 宏S_ISFIFO可用于确定一个描述符 ...
- php socket 简单理解
以下内容转自:https://www.cnblogs.com/loveyoume/p/6076101.html 和 https://www.cnblogs.com/WuNaiHuaLuo/p/6107 ...