JavaScript 扯几句单线程相关

众所周知,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了,打印出来的还是不正常的。

对于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在同一个时间上只能处理一件事.他不像C,Java等这些多线程的,可以开不同的线程去同时处理多件事情. 那么为什么别的语言都 ...

  2. JavaScript 的异步和单线程

    问题 Q:下面的代码是否能满足sleep效果? var t = true; setTimeout(function(){ t = false; }, 1000); while(t){ } alert( ...

  3. JavaScript 对象 - 与属性的相关知识

    function inherit(p){ if(p == null) throw TypeError(); if(Object.create) return Object.create(p); var ...

  4. JavaScript跨浏览器处理事件以及相关对象

    主流的浏览器和IE浏览器在处理事件和事件对象上是有所区别的,我们一般会通过EventUtil进行封装,这样,就可以正常的跨浏览器处理事件了,本文的主要内容总结自<JavaScript高级程序设计 ...

  5. 0182 JavaScript执行机制:单线程,同步任务和异步任务,执行栈,消息队列,事件循环

    以下代码执行的结果是什么? [结果是1 2 3 ] console.log(1); setTimeout(function () { console.log(3); }, 1000); console ...

  6. JavaScript深入浅出3-语句

    慕课网教程视频地址:Javascript深入浅出 程序由语句组成,语句遵守特定语法规则 块 block  {}   没有块级作用域 声明    var 异常   try catch finally 函 ...

  7. JavaScript中forEach的用法相关

    首先说下JavaScript的forEach的标准格式. 为数组中的每个元素执行指定操作. array1.forEach(callbackfn[, thisArg]) 参数 定义 array1 必需. ...

  8. JavaScript中的DOM及相关操作

    一.什么是DOM JavaScript由ECMAScript.DOM和BOM三部分组成,其中DOM代表描述网页内容的方法和接口,即文档对象模型(Document Object Model).在网页上, ...

  9. JavaScript常用語句

    1.document.write(""); 输出语句2.JS中的注释为//3.传统的HTML文档顺序是:    document->html->(head,body)4 ...

随机推荐

  1. FZU 2107 Hua Rong Dao(暴力回溯)

    dfs暴力回溯,这个代码是我修改以后的,里面的go相当简洁,以前的暴力手打太麻烦,我也来点技术含量.. #include<iostream> #include<cstring> ...

  2. ExtJS4.1自带API打不开的问题解决

    在ext官网个下载的最新版本的extjs,本来想看看里面的docs文档的,结果却发现打不开,总是转个不停,于是就打开index.html的源码,看到引入ext的js文件的时候,看到引入的是ext.js ...

  3. PAT (Advanced Level) 1046. Shortest Distance (20)

    处理一下前缀和. #include<iostream> #include<cstring> #include<cmath> #include<algorith ...

  4. SQL复习五(索引)

    SQL索引在数据库优化中占有一个非常大的比例, 一个好的索引的设计,可以让你的效率提高几十甚至几百倍,在这里将带你一步步揭开他的神秘面纱. 1.1 什么是索引? SQL索引有两种,聚集索引和非聚集索引 ...

  5. mrql初级教程-概念、使用(一)

    以下是本人原创,如若转载和使用请注明转载地址.本博客信息切勿用于商业,可以个人使用,若喜欢我的博客,请关注我,谢谢!博客地址 感谢您支持我的博客,我的动力是您的支持和关注!如若转载和使用请注明转载地址 ...

  6. Quick Cocos2dx 与 Eclipse 连真机debug遇到的问题

    今天下午解决了因为偷懒一直忍受的两个让我不爽很久了的问题: 1Eclipse无法连接手机调试的问题. 在设备管理器中看到的Android设备有黄色的感叹号, 说明驱动不是最新的. 按照网上搜到的解决方 ...

  7. python_eval的用法

    1. eval用法: 将字符串str当成有效的表达式来求值并返回计算结果. 2. eval的功能: math当成一个计算器很好用. 将字符串转换为list,tuple,dict. 3. 举例 # -* ...

  8. spring MVC 初探 (HelloWorld)

    1.使用spring MVC 需要导入相关jar包 2.web.xml 启用spring MVC <servlet> <servlet-name>spring3mvc</ ...

  9. SD卡初始化以及命令详解

    SD卡是嵌入式设备中很常用的一种存储设备,体积小,容量大,通讯简单,电路简单所以受到很多设备厂商的欢迎,主要用来记录设备运行过程中的各种信息,以及程序的各种配置信息,很是方便,有这样几点是需要知道的 ...

  10. STM32驱动AT24CXX系列芯片

    AT24Cxx系列EEPROM是由美国Mcrochip公司出品,1-512K位的支持I2C总线数据传送协议的串行CMOS E2PROM,可用电擦除,可编程自定时写周期(包括自动擦除时间不超过10ms, ...