众所周知,Javascript是单线程执行的,这也就是说:JavaScript在同一个时间上只能处理一件事。他不像C,Java等这些多线程的,可以开不同的线程去同时处理多件事情。

那么为什么别的语言都可以这么方便的去开多个线程去同时执行多个任务,JavaScript却不行呢?

“天将降大任于斯人也,必先苦其心志,劳其筋骨,饿其体肤,空乏其身,行指乱其所为,所以动心忍性,曾益其所不能”
                                                --《孟子》

正是因为JavaScript背负着重大的使命,所以他只能默默的看着别人拥有多线程。他作为浏览器脚本语言,只要是在于和用户进行交互/处理前端数据/操作DOM。

以代码举例吧:

  function addDom(){
var html = document.createElement("div");
html.innerHTML = "This is div "+i;
document.getElementById("myDiv").appendChild(html);
}
function deleteDom(){
var myDiv = document.getElementById("myDiv");
//if(myDin.childNodes[0]){
myDiv.removeChild(myDin.childNodes[0]);
//}
}

注意:以上代码注释部分可以让逻辑变的更严谨,此处需要报错已证明观点,所以加以注释。

按照以上代码执行addDom函数是能正确的生成这么一个DOM的吧,即便是在addDom函数还在执行过程中去执行deleteDom,deleteDom也将会在addDom执行完后才执行,那么就能完整的走完一个DOM的添加和删除操作了,这正是因为JavaScript是单线程。

现在我们假如JavaScript可以有多线程,那么我们让一个线程执行addDom函数的时候,在addDom还在执行的过程中再去执行deleteDom,这时候将会再开一个线程来执行,这时候浏览器脑子短路了,它不知道以哪个为主了...如果先执行完了deleteDom,那么效果就是即报了错还没达到想要的效果。

综上所述,JavaScript确实不适用于多线程,为了交互,他只能独自忍受了(所以当报错不会继续向下执行的时候,各位就别喷JavaScript了,好好检查自己写的代码才是这时候该做的)。

事件列队和异步执行

既然JavaScript是单线程执行的,那么有很多事件需要执行的时候,肯定需要排好队一个个来的吧。接下来我们就扯扯事件队列和异步。

JavaScript的事件队列里就是编排着接下来将要被逐个执行的事件,只有当前一个任务被执行完了,才会接下来执行后面一个任务。当我们触发一个事件,那么这个事件会被加入到事件列表末尾,当然不能插队咯,毕竟都是良民呐~

以上就是对事件队列的简单介绍,那么异步又是怎么回事呢?

Javascript语言将任务的执行模式分成两种:同步(Synchronous)和异步(Asynchronous)。

同步就是按照事件队列的顺序,有条不紊的执行下来。

异步则不同,每个任务都可以有一或多个回调函数(callback),当前面那一个任务执行完后,不去执行下一个任务,先执行其本身存在的回调函数,而下一个任务不等前一个任务结束,自顾自的开始执行了,这时候执行顺序就不一样的,产生异步了。(注意:这里并不说明使用回调函数即产生异步哦)

贴上代码:

  var num = 0;
function firstFn(){
num +=1;
};
function secondFn(value){
if(value === 1){
console.log("The num is 1"); //The num is 1
} else{
console.log("The num still 0");
}
}
firstFn();
secondFn(num);

以上是能正常打印出来的,因为先执行了第一个函数,所以这时num已经被加1了,所以判断生效。

  var num = 0;
function firstFn(){
setTimeout(function(){
num +=1;
},0); // 这里我们用setTimeout做了异步处理
};
function secondFn(value){
if(value === 1){
console.log("The num is 1");
} else{
console.log("The num still 0"); //The num still 0
}
}
firstFn();
secondFn(num);

这时候,再这样执行就没用了。因为setTimeout将num++的事件放到了事件列表的末尾去了,second(num)是在它的前面,所以现在执行是打印 The num still 0。那么怎么证明该事件被放到最后了呢?看下面的代码:

  <div id="myDiv" onclick="addEvent()">click me</div>
  var num = 0;
function firstFn(){
setTimeout(function(){
num +=1;
},0);
};
function secondFn(value){
if(value === 1){
console.log("The num is 1"); //The num is 1
} else{
console.log("The num still 0");
}
}
firstFn();
function addEvent(){
secondFn(num);
}

当我们点击id为myDiv的div的时候,将触发click事件吧,该事件会调用addEvent函数吧,addEvent函数会在事件队列的末尾加入新的需要执行的事件吧。这时候我们点击该div,就会打印 The num is 1 了。

同理理解setInterval。

下面顺便贴一段有小伙伴提问过的问题代码:

正常的代码:

  var i = 3;
for(;i>0;i--){
console.log(i); //打印顺序:3 2 1
};

"不正常"的代码:

  var i = 3;
for(;i>0;i--){
setTimeout(function(){console.log(i);},0); //打印顺序 0 0 0
};

人家问的就是为什么都设置延迟时间为0了,打印出来的还是不正常的。这也是因为异步,当函数被执行的时候,i的值已经为0。

对于setTimeout的通常描述:给定一个回调及N毫秒的延迟,setTimeout将会在N毫秒后运行该回调。

所以大多数情况下,这个描述只能算大致正确,不能算完全正确。

而且setTimeout还附带了个隐藏的可大可小的坑(将由线程阻塞导致):

  var start = new Date;
setTimeout(function(){
var end = new Date;
console.log("End Time: ",end - start," ms"); // 有几次打印的是End Time: 1001 ms ,这还是在没有其他阻塞的,只运行这一个事件的情况下出现偏差
},1000);

所以上面那个描述的N毫秒将在某些情况下会出现偏差。
好了,就写这么多先吧。明天还得上班呢,今天算拖的很晚了...还是手机编辑的,本来打算睡觉,写一半没完成,心里怪难受的...
如理解有偏差,还望大家不吝指教,大家一起交流才能更好的进步。

JavaScript 单线程相关的更多相关文章

  1. JavaScript 扯几句单线程相关

    JavaScript 扯几句单线程相关 众所周知,Javascript是单线程执行的,这也就是说:JavaScript在同一个时间上只能处理一件事.他不像C,Java等这些多 线程的,可以开不同的线程 ...

  2. 细说JavaScript单线程的一些事

    标签: JavaScript 单线程 首发地址:码农网<细说JavaScript单线程的一些事> 最近被同学问道 JavaScript 单线程的一些事,我竟回答不上.好吧,感觉自己的 Ja ...

  3. JavaScript单线程和异步机制

    随着对JavaScript学习的深入和实践经验的积累,一些原理和底层的东西也开始逐渐了解.早先也看过一些关于js单线程和事件循环的文章,不过当时看的似懂非懂,只留了一个大概的印象:浏览器中的js程序时 ...

  4. javascript单线程那些事

    首先,说下为什么 JavaScript 是单线程? 总所周知,JavaScript是以单线程的方式运行的.说到线程就自然联想到进程.那它们有什么联系呢? 进程和线程都是操作系统的概念.进程是应用程序的 ...

  5. JavaScript单线程和浏览器事件循环简述

    JavaScript单线程 在上篇博客<Promise的前世今生和妙用技巧>的开篇中,我们曾简述了JavaScript的单线程机制和浏览器的事件模型.应很多网友的回复,在这篇文章中将继续展 ...

  6. 浏览器中Javascript单线程分析

    线程这个特性对于一门语言环境来说是尤其重要的,在Java/C++环境下都提供了多线程API操作. 但在Javascript中据说代码执行时单线程的,大量计算的逻辑会阻塞浏览器HTML渲染,但setTi ...

  7. 我理解的javascript单线程机制

    废话不多说,我们先来看几个例子: 1. setTimeout( console.log(2); result:  2 1   2.   console.log(100 setTimeout( cons ...

  8. javascript 事件相关使用总结01

    javascript 事件相关使用总结01 这里总结一下js事件相关的经验. addEventLinstener()介绍 注册事件最基础的函数是这个 target.addEventListener(t ...

  9. 浏览器UI多线程及JavaScript单线程运行机制的理解

    在上一篇博客中,我对jQuery的队列(queue)机制和动画(animate)机制做了一个深入的解析,在animate的实现机制其核心是依靠queue来完成的,其中在jQuery的链式调用部分,之前 ...

随机推荐

  1. 关于viewpager 里嵌套 listview 同时实现翻页功能的“java.lang.IllegalStateException: The specified child..."异常处理

    这几天做项目用到了ViewPager,因为它可以实现左右划动多个页面的效果,然后 再每个页面里使用ListView,运行时总是出现”PagerAdapter java.lang.IllegalStat ...

  2. Spring IOC 源码浅析

    控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题,也是轻量级的Spring框架的核心. 控制反转一般分为两种类型,依赖注入 ...

  3. HoloLens开发手记 - 测试 Testing

    测试HoloLens应用的做法和测试Windows应用很类似.所有常规的内容都应该被考虑在内(功能.互操作性.性能.安全性.可靠性等等),然而有些特性是HoloLens特有的,在PC或者手机上无法测试 ...

  4. 东大OJ-麦森数

    1064: 麦森数 时间限制: 1 Sec  内存限制: 128 MB 提交: 52  解决: 9 [提交][状态][讨论版] 题目描述 形如2P-1的素数称为麦森数,这时P一定也是个素数.但反过来不 ...

  5. 常用数据库高可用和分区解决方案(2) — MongoDB篇

    MongoDB是当前比较流行的文档型数据库,其拥有易使用.易扩展.功能丰富.性能卓越等特性.MongoDB本身就拥有高可用及分区的解决方案,分别为副本集(Replica Set)和分片(shardin ...

  6. 给li设置float浮动属性之后,无法撑开外层ul的问题。(原址:http://www.cnblogs.com/cielzhao/p/5781462.html)

    最近在项目中有好几次遇到这个问题,感觉是浮动引起的,虽然用<div style="clear:both"></div>解决了,但自己不是特别明白,又在网上查 ...

  7. MySQL修改,表结构大幅修改

    ------------------create table t_video_file_temp( video_id bigint not null comment '视频Id', file_md5 ...

  8. springMVC之web.xml配置

    <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http:// ...

  9. c# Winform 开发分屏显示应用程序

    分屏显示即可把一台主机内运行的多个程序分别显示在不同的两个(或多个)屏幕上.目前市面上主流的显卡都支持分屏显示(显示双屏幕),如果需要显示2个以上的屏幕,则应使用“拖机卡”类的硬件. 设置分屏显示的两 ...

  10. 【BZOJ 3050】【USACO2013 Jan】Seating 线段树

    线段树维护4个标记, 昨天互测时题意理解错了,今天上午才发现. #include<cstdio> #include<cstring> #include<algorithm ...