今天在偶然在网上看到一个JavaScript的面试题,尝试着看了一下,很正常的就做错了,然后给我们前端做,哈哈,他居然也顺理成章做的错了,代码大概是这样的

        /*1 下面代码会怎样执行?执行结果是什么*/
var i=true;
setTimeout('stoploops()', 2000);
loops();
function loops(){
alert('no hello world!');
while(i){ }
}
function stoploops(){
i=false;
alert('hello world!');
}

粗略的看下上面的代码,你的第一感觉是浏览器在网页打开两秒后执行stoploops函数,将i的值变成false随后弹出hello world!,然后执行loops函数弹出no hello world!,由于i的值为false所以不会进入死循环,所以代码执行结束,但代码的实际运行情况并不是这样。

经过本人查阅资料仔细一研究后,发现事情并不简单,这个问题牵连出了JavaScript代码的在浏览器中的运行机制,而setTimeout和setInterval函数也算是两个彻头彻尾的“大骗子”,而相关关于介绍setTimeout() 的文档也是:方法用于在指定的毫秒数后调用函数或计算表达式。

但是在很多情况下setTimeout和setInterval函数调用的函数并不一定会在参数指定的时间内执行,比如上面的代码;上面的代码最终运行结果是:浏览器在网页打开的第一时间会先执行loops()函数,随即弹出no hello world!弹窗,然后由于i=true,所以会无限循环,直到停电,永远都不会执行stoploops函数。

如果你是普通撸码玩家,对于这种现实也许有点无法接受,因为常规的代码都是顺序执行的,这有点违背常理的味道在里面,但是事实就是这样,代码会按照我所说的第二种方式执行。

而且弄懂为什么会这样不安常规的执行,对于深入学习和理解JS都是有很大必要的。

下面就来揭开这个问题的神秘面纱,其执行顺序错位其本质就是由于:JavaScript引擎是单线程运行的,浏览器无论在什么时候都只且只有一个线程在运行JavaScript程序. 

当然理解这句话的意思你首先得知道什么是线程:线程是程序执行流的最小单元。关于线程与进程相关细节的东西也比较复杂,一句话也说不清楚,当然在此处为了理解后面的内容,你可以简单的把线程理解为一个小型“cpu”,它在同一时间内只能做一件事情,就好比假如一个人,在同一时间内,他在吃饭的时候,就开启了一个负责吃饭的线程,这个线程就只能吃饭,不能同时做其他的事情,如果他想在吃饭的时候“边吃饭边看电视”,就要启用另一个线程,一个线程负责吃饭,一个线程负责看电视(实际的这两个线程执行是交替执行,并不是并行,所以边吃饭边看电视会有引号)。这么说我想你就能理解上面那句:JavaScript引擎是单线程运行的,浏览器无论在什么时候都只且只有一个线程在运行JavaScript程序. 简单的说就是一个浏览器(浏览器就是一个进程)负责执行JS代码的线程只有一个,而setTimeout和setInterval使用了障眼法,制造了一种假象,好像用他俩执行的函数是单独启用了新的线程来执行的,其实并不会有新的线程被启用,从语言的设计角度来讲,JavaScript单线程运行时有它的优点的,JavaScript作为浏览器脚本语言,其主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题(想想要是真有一天,JS变成了多线程,要是把复杂线程冲突和数据同步问题都丢给JS,丢给前端,他会说我他M只是个画界面的,what fuck?Greet your family for me)。

所以JavaScript把代码任务分成了两种,一种是同步任务(synchronous)的代码,一种是异步任务(asynchronous)的代码(异步任务代码对应着一个事件队列,用于控制异步代码的执行顺序),JavaScript引擎会优先执行同步任务的代码,等所有同步任务的代码执行完成后,才会去顺序执行异步代码,如果在同步代码执行过程中出现CPU计算不过来,会消耗较长时间,那也是先等同步代码执行完成后,才会按顺序执行异步代码,我们一般常规书写的代码都是同步任务代码,而setTimeout和setInterval中执行的代码即为异步任务代码。所以现在回看上面的题目,由于loops函数是同步任务代码,JavaScript引擎会先执行loops函数,但是loops函数有一个死循环,所以JavaScript引擎线程会长期处于阻塞状态,无法执行后续的代码。。。终于真相大白!

扩展:

1,通过上面的学习,如果以后在遇到同步任务相对耗时时,我们可以将耗时的代码放到setTimeout中去执行,这样JavaScript引擎就会优先的去执行可快速执行的同步任务代码,现将可以渲染的部分先渲染出来,使用户体验更为良好

2,JavaScript引擎是单线程运行的!=整个网页都是单线程的,浏览器内核实现允许多个线程异步执行,除了javascript引擎线程外,还会有界面渲染线程,浏览器事件触发线程,相关请求线程等,

界面渲染线程:该线程负责渲染浏览器界面HTML元素,当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行,该线程与JavaScript引擎线程是互斥的,所以就不难理解为什么当JavaScript引擎线程被阻塞后界面渲染线程就渲染HTML元素,导致界面一片空白了

事件触发线程:当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待JS引擎的处理。这些事件可来自JavaScript引擎当前执行的代码块如setTimeOut、也可来自浏览器内核的其他线程如鼠标点击、AJAX异步请求等,但由于JS的单线程关系所有这些事件都得排队等待JS引擎处理。

定时触发线程:浏览器模型定时计数器并不是由JavaScript引擎计数的,因为JavaScript引擎是单线程的,如果处于阻塞线程状态就计不了时,它必须依赖外部来计时并触发定时

3,既然JS是单线程语言,XMLHttpRequest对象实现AJAX异步请求是如何做到的?

其实请求确实是异步的,不过这请求是由浏览器新开一个线程请求,当请求的状态变更时,如果先前已设置回调,这异步线程就产生状态变更事件放到 JavaScript引擎的处理队列中等待处理,当任务被处理时,JavaScript引擎始终是单线程运行回调函数,具体点即还是单线程运行 onreadystatechange所设置的函数,但是如在执行AJAX异步请求之前同步任务中有可以阻塞JavaScript引擎线程代码,界面已久会卡死,无法进行其他操作,直到同步任务执行完成,解除阻塞,界面才可以做其他事情

参考文章:

http://www.ruanyifeng.com/blog/2014/10/event-loop.html

http://www.iamued.com/qianduan/1645.html

JavaScript运行机制的学习的更多相关文章

  1. 从setTimeout谈JavaScript运行机制

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

  2. JavaScript 运行机制 & EventLoop

    JavaScript 运行机制 & EventLoop 看阮老师博客和自己的理解,记录的学习笔记,js的单线程和 事件EventLoop 机制. 1. JavaScript是单线程 JavaS ...

  3. 深入理解JavaScript运行机制

    深入理解JavaScript运行机制 前言 本文是写作在给团队新人培训之际,所以其实本文的受众是对JavaScript的运行机制不了解或了解起来有困难的小伙伴.也就是说,其实真正的原理和本文阐述的并不 ...

  4. javascript运行机制

    太久没更新博客了,Javascript运行机制 Record it 1.代码块 JavaScript中的代码块是指由<script>标签分割的代码段.例如: <script type ...

  5. JavaScript运行机制详解

    JavaScript运行机制详解   var test = function(){ alert("test"); } var test2 = function(){ alert(& ...

  6. 深入浅出JavaScript运行机制

    一.引子 本文介绍JavaScript运行机制,这一部分比较抽象,我们先从一道面试题入手: console.log(1); setTimeout(function(){ console.log(3); ...

  7. javascript 运行机制 事件循环 浏览器缓存 (慕课网 前段跳槽面试必备 4-1,4-2,4-3)

    4-1 渲染机制:-1-,什么是DOCTYPE及其作用?DTD(document type definition,文档类型定义)是一系列的语法规则,用来定义XML或(X)HTML的文件类型,浏览器会使 ...

  8. JavaScript运行机制与setTimeout

    前段时间,老板交给了我一个任务:通过setTimeout来延后网站某些复杂资源的请求.正好借此机会,将JavaScript运行机制和setTimeout重新认真思考一遍,并将我对它们的理解整理如下. ...

  9. Javascript 运行机制

    先看一下下面这段js代码: console.log('1'); setTimeout(function(){ console.log('2'); },0); console.log('3'); 请问打 ...

随机推荐

  1. MediaWIKI部署流程

    1.下载mediawiki,地址:https://www.mediawiki.org/wiki/MediaWiki 2.下载xxamp集成软件,地址:https://www.apachefriends ...

  2. Etcd安全配置之Basic Auth认证

    <中小团队落地配置中心详解>文章中我们介绍了如何基于Etcd+Confd构建配置中心,最后提到Etcd的安全问题时说了可以使用账号密码认证以达到安全访问的目的,究竟该如何开启认证以及怎么设 ...

  3. Go语言学习笔记十: 结构体

    Go语言学习笔记十: 结构体 Go语言的结构体语法和C语言类似.而结构体这个概念就类似高级语言Java中的类. 结构体定义 结构体有两个关键字type和struct,中间夹着一个结构体名称.大括号里面 ...

  4. mac 上安装 redis

    1.从http://redis.io 下载redis包,这里选择了redis-3.2.3 2.将下载的 redis-3.2.3.tar.gz 包拷贝到 /usr/local 目录 3.执行 sudo ...

  5. GDAL并行I/O

    和导师在Transactions in GIS 上发表的关GDAL并行I/O方面的文章(SSCI, IF=0.906)http://onlinelibrary.wiley.com/doi/10.111 ...

  6. CSS的定位问题总结

    CSS 定位和浮动 CSS 为定位和浮动提供了一些属性,利用这些属性,可以建立列式布局,将布局的一部分与另一部分重叠,还可以完成多年来通常需要使用多个表格才能完成的任务. 定位的基本思想很简单,它允许 ...

  7. PTA (Advanced Level) 1028 List Sorting

    List Sorting Excel can sort records according to any column. Now you are supposed to imitate this fu ...

  8. webstorm皮肤外观样式快速设置,CMD的使用方法,webstorm11激活方法

    一.皮肤外观设置 因为这里是上班时间写的,其客套话就不多bb.步入正题 1.首先设置webstorm整体面板颜色 file->settings->Appearance&Behavi ...

  9. 13.Promise 对象

    Promise 对象 Promise 对象 Promise 的含义 Promise 是异步编程的一种解决方案,比传统的解决方案--回调函数和事件--更合理和更强大.它由社区最早提出和实现,ES6 将其 ...

  10. [转]微信小程序之加载更多(分页加载)实例 —— 微信小程序实战系列(2)

    本文转自;http://blog.csdn.net/michael_ouyang/article/details/56846185 loadmore 加载更多(分页加载) 当用户打开一个页面时,假设后 ...