众所周知,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运行机制的更多相关文章

  1. 如何通过setTimeout理解JS运行机制详解

    setTimeout()函数:用来指定某个函数或某段代码在多少毫秒之后执行.它返回一个整数,表示定时器timer的编号,可以用来取消该定时器. 例子 ? 1 2 3 4 5 console.log(1 ...

  2. 从setTimeout谈JavaScript运行机制

    从setTimeout说起 众所周知,JavaScript是单线程的编程,什么是单线程,就是说同一时间JavaScript只能执行一段代码,如果这段代码要执行很长时间,那么之后的代码只能尽情地等待它执 ...

  3. 浅谈js运行机制

    前言 因为js的运行机制十分重要,理解起来也十分抽象,仍还是在这里做个记录,加深自己的记忆. 总之,希望本文的内容能够对您的学习或者工作有所帮助.另,如果有任何的错误或者不足请指正! 如何理解js单线 ...

  4. 从浏览器多进程到JS单线程,JS运行机制的一次系统梳理

    前言 见解有限,如有描述不当之处,请帮忙及时指出,如有错误,会及时修正. ----------超长文+多图预警,需要花费不少时间.---------- 如果看完本文后,还对进程线程傻傻分不清,不清楚浏 ...

  5. 从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理

    前言 来源:https://dailc.github.io/2018/01/21/js_singlethread_eventloop.html 见解有限,如有描述不当之处,请帮忙及时指出,如有错误,会 ...

  6. js 运行机制

    <script> console.log(1) setTimeout(function(){ console.log(3) },0) console.log(2) </script& ...

  7. Js 运行机制 (重点!!)

    一.引子 本文介绍JavaScript运行机制,这一部分比较抽象,我们先从一道面试题入手: 这一题看似很简单,但如果你不了解JavaScript运行机制,很容易就答错了.题目的答案是依次输出1 2 3 ...

  8. Js 运行机制 event loop

    Js - 运行机制 (Even Loop) Javascript 的单线程 - 引用思否的说法: JavaScript的一个语言特性(也是这门语言的核心)就是单线程.什么是单线程呢?简单地说就是同一时 ...

  9. js 运行机制简单了解

    一.如何理解 JS 的单线程? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊. JavaScrip ...

随机推荐

  1. git fatal:HttpRequestException encountered

    网上查了一下发现是Github 禁用了TLS v1.0 and v1.1,必须更新Windows的git凭证管理器,才行. https://github.com/Microsoft/Git-Crede ...

  2. Android-SqliteSQL语句大全

    SqliteSQL语句大全 创表语句: create table student_table(_id integer primary key autoincrement, name text, age ...

  3. pro1

    #include<iostream> using namespace std; int main(void) { int i,a[],sum; cin>>i; for(i=0; ...

  4. C#泛型使用小记

    最近C#的泛型使用频次略多,特在此记下一个印象深刻的. 情景如下, 基类BaseClass 有一系列的子类 SubClass1, SubClass2, SubClass3... 且其构造函数的参数较多 ...

  5. ffmpeg学习(三)——ffmpeg+SDL2 实现简单播放器

    本篇实现基于ffmpeg动态库用测试程序播放本地文件和RTSP视频流. 参考文章:http://blog.csdn.net/leixiaohua1020/article/details/8652605 ...

  6. 【node错误】/usr/bin/env: node: No such file or directory

    背景 安装了node后,执行npm run xxx的命令的时候,报错,提示如下: /usr/bin/env: node: No such file or directory 步骤 1. 什么玩意,执行 ...

  7. (zxing.net)一维码Code 128的简介、实现与解码

    一.简介 一维码Code 128:1981年推出,是一种长度可变.连续性的字母数字条码.与其他一维条码比较起来,相对较为复杂,支持的字元也相对较多,又有不同的编码方式可供交互运用,因此其应用弹性也较大 ...

  8. UDP实现一个简易的聊天室 (Unity&&C#完成)

    效果展示(尚未完善) UDP User Data Protocol 用户数据报协议 概述 UDP是不连接的数据报模式.即传输数据之前源端和终端不建立连接.使用尽最大努力交付原则,即不保证可靠交付. 数 ...

  9. ES6——Symbol数据类型

    什么是 Symbol ? Symbol 表示独一无二的值,他是js中的 第七种数据类型. 基本的数据类型:null, undefined number boolean string symbol 引用 ...

  10. VS2015 IIS Express 无法启动 解决办法(转)

    因为安装各种乱七八糟的软件,然后不小心把IIS Express卸载掉了,网上下载了一个IIS Express 7,安装之后本地使用VS 2015无法启动调试,F5 无法启动IIS, 再次F5调试,没有 ...