JS高级——浏览器的线程
基本概念
1、js的执行过程是单线程的模式,也就是同步进行,只有前面的代码执行完了才会往下面执行
2、但是执行js代码也只是浏览器的线程之一所负责的事情,这个线程被称为js引擎,浏览器还具有其他线程:界面渲染线程(UI)、浏览器事件触发线程(控制交互,响应用户)、http请求线程(处理请求,而ajax发送请求则会委托浏览器新开一个http线程)、EventLoop轮询线程(负责轮询消息队列)
3、浏览器中js代码的作用:执行JavaScript代码 、对用户的输入(包含鼠标点击、键盘输入等等)做出反应 、处理异步的网络请求
js单线程
1、单线程的含义是js只能在一个线程上运行,也就说,js同时只能执行一个js任务,其它的任务则会排队等待执行。
2、js是单线程的,并不代表js引擎线程只有一个。js引擎有多个线程,一个主线程,其它的后台配合主线程。
3、多线程之间会共享运行资源,浏览器端的js会操作dom,多个线程必然会带来同步的问题,所有js核心选择了单线程来避免处理这个麻烦。js可以操作dom,影响渲染,所以js引擎线程和UI线程是互斥的。这也就解释了js执行时会阻塞页面的渲染
js消息队列
1、JavaScript运行时,除了一个运行线程,引擎还提供一个消息队列,里面是各种需要当前程序处理的消息。新的消息进入队列的时候,会自动排在队列的尾端
2、单线程意味着js任务需要排队,如果前一个任务出现大量的耗时操作,后面的任务得不到执行,任务的积累会导致页面的“假死”。这也是js编程一直在强调需要回避的“坑”
js执行任务方式
1、首先js任务分两种:同步任务、异步任务
2、同步任务:在主线程排队支持的任务,前一个任务执行完毕后,执行后一个任务,形成一个执行栈,线程执行时在内存形成的空间为栈,进程形成堆结构,这是内存的结构。执行栈可以实现函数的层层调用。注意不要理解成同步代码进入栈中,按栈的出栈顺序来执行。
3、异步任务:会被主线程挂起,不会进入主线程,而是进入消息队列,而且必须指定回调函数,只有消息队列通知主线程,并且执行栈为空时,该消息对应的任务才会进入执行栈获得执行的机会。
4、主线程说明:
(1)所有同步任务都在主线程上执行,形成一个执行栈。
(2)主线程之外,还存在一个”任务队列”(消息队列)。只要异步任务有了运行结果,就在”任务队列”之中放置一个事件。
(3)一旦”执行栈”中的所有同步任务执行完毕,系统就会读取”任务队列”(消息队列),看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
(4)主线程不断重复上面的第三步。
5、消息队列说明:
(1)消息队列队列(或者叫任务队列)是一个事件的队列,IO响应时(鼠标点击等输入输出设备的操作),会往队列中添加一个消息,此时说明相关的异步代码到了执行的时机,可以进入主线程的执行栈了。
(2)主线程读取消息队列,可以读取到对应的事件。
(3)消息队列可以响应IO事件,还有用户产生的事件(比如点击鼠标,页面滚动),只要指定了回调函数,就会进入消息队列,等待EventLoop轮询线程处理,是否可以进入主线程的执行栈。
(4)消息和回调函数相互联系的含义:主线程读到消息,就会执行相应的回调函数;进入消息队列的消息,必须对应相应的回调函数,否则这个消息会被丢弃不会进入消息队列。
(5)消息队列是一个先进先出的队列结构,这就决定了它的执行顺序,先产生的消息会被主线程先读取,会不会执行则会先检查一下执行时间,因为存在setTimeout等定时函数,这类事件产生的消息进入到消息队列,被执行的时机取决与它在队列中的位置和执行时间有关。【使用setTimeout能够避免阻塞UI线程就是这个原因】。
5、需要注意的是:执行栈中的代码(同步任务),总是在读取”任务队列”(异步任务)之前执行。
EventLoop
1、主线程从”任务队列”中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。
2、简单说,浏览器的两个线程:一个负责程序本身的运行,称为”主线程”;另一个负责主线程与其他进程(主要是各种I/O操作)的通信,被称为”Event Loop线程”(可以译为”消息线程”)。
3、由于js是运行在单线程上的,所有浏览器单独开启一个线程来处理事件消息的轮询,避免阻塞js的执行。
异步代码执行逻辑
1、每当遇到I/O的时候,主线程就让EventLoop线程去通知相应的I/O程序,然后接着往后运行,所以不存在等待时间。等到I/O程序完成操作,EventLoop线程把消息添加到消息队列,主线程就调用事先设定的回调函数,完成整个任务。
2、js的ajax是new XMLHttpRequest()对象实现的,浏览器会新开一个线程来处理http请求,这就是ajax能够实现局部刷新的同时,还能响应用户交互的原因。
定时器
1、前面也提到了定时器,定时器是会在进入消息队列,这也就和异步代码的执行逻辑一样了。它在”消息队列”的尾部添加一个消息,因此要等到同步任务和”消息队列”现有的任务都处理完,才会得到执行的机会,还要看定时器设置的时间是否到了才会执行。
<script>
for(var i = 0 ; i < 10; i++){
setTimeout(function(){
console.log(i);//打印10次10
},0);
}
</script>
所以,只有等到主线程的任务执行完之后,setTimeout中的事件才会被执行,虽然时间间隔是0秒,但是必须等主线程任务完成,所以最后打印的都是10
2、可以用闭包来解决问题,每次执行for循环的时候,把函数作为返回值给setTimeout作为参数,函数里面存着从for循环里面拿到的每一个值,下面代码会返回多个函数,每个函数的j值都不一样
<script>
for(var i = 0; i< 3; i++){
function foo(j){
// var j;
// j = 实参
//j = i
return function(){
console.log(j);
};
}
//0
var f = foo(i);
setTimeout(f, 0);
}
</script>
参考:
http://blog.csdn.net/w2765006513/article/details/53743051
https://www.cnblogs.com/haodawang/articles/5850822.html
最新文章
- Zabbix 3.0 安装笔记
- 2016.8.16 JQuery学习记录
- struts2视频学习笔记 01-02
- 《学习OpenCV》练习题第五章第一题ab
- java操作spark1.2.0
- 【C语言】-循环的嵌套
- HZNU1015: 矩阵排序
- Tr A(HDU 1575 快速矩阵幂模板)
- oracle 导入txt
- 二叉堆(C#)
- 数据库CAST()函数和CONVERT()函数比较
- 重温吕鑫MFC教学视频(一)
- 洛谷P4302 [SCOI2003]字符串折叠(区间dp)
- Java读取接口中的数据,并保存到txt文件中!
- Srt字幕文件解析
- CALL与retn
- Java 类名.class与类名.this 的区别?
- idea 改变version control
- JS实现一个基于对象的链表
- 中国移动CMPP协议错误码
热门文章
- Ubuntu 16.04下UML建模PowerDesigner的替代ERMaster和MySQL Workbench
- SiteMesh2-sitemesh.xml的PageDecoratorMapper映射器的用法
- css3 字体自适应
- 百度LBS云搜索时报错 &;quot;filter:area is not filteable field, please set property in the cloud-storage
- Unity编程笔录--ulua+PureMVC框架简单热更新使用
- DDM实践:数据库秒级平滑扩容方案
- HDU 1299Diophantus of Alexandria
- Changing the Output Path in your Web Applications is a bad idea
- JavaScript Patterns 2.1 Writing Maintainable Code
- 不仅开源,而且对企业应用完全免费!ExtAspNet弃用GPL v2,拥抱Apache License 2.0(转)