JavaScript—线程机制与事件机制
程序员文章站
2024-03-24 15:26:46
...
1.进程与线程
1.基本概念:
(1).进程:是程序的一次执行,它占用一片独有的内存空间,程序运行就启动了进程。
(2).线程:是进程内的一个独立执行单元,是程序执行的一个完整流程。
2.进程和线程关系
*一个程序中可以有一个或者多个进程;
(如在一个工厂中可以有一个车间(单核)或多个车间(多核),就是多进程)
*一个进程中可以有一个或者多个线程;
(如一个车间可以有一个工人工作,或多个工人工作,只有一个cpu工人轮流使用)
若一个进程中有多个线程运行,则为多线程程序 ;
若一个进程中只有一个线程运行,则为单线程程序 ;
(若一个程序有两个进程,每个进程都只有一个线程,则该程序是单线程程序;只看对应一个进程中有几个线程)
*一个进程内的数据可以供其中的多个进程直接共享
*多个进程之间的数据是不能直接共享的
3. 相关问题:
(1).何为多进程与多线程??
答:多进程运行:一个应用程序可以同时启动多个实例运行;
多线程:在一个进程内,同时有多个线程运行;
(2).比较单线程与多线程??
答:多线程:可以一起运行a和b,可以做多件事情,多线程则又主线程和分线程
*多线程优点:能有效提高CPU的利用效率
(多线程cpu不会停歇,而单线程中cpu执行每一个时都有个停歇);
*多线程缺点:创建多线程开销
线程间切换开销
死锁与状态同步问题
(CUP一时刻只能做一个)
多线程执行方式若是单核的有两个线程:
两个线程a、b同时进行:cup是a先执行一会暂停,再让b执行一会暂停,
依次切换执行,,直到最后ab一起完成,则会有切换开销;
单线程:同一时间只能运行一个,用一时刻只能做一个事情,a执行完执行b
*顺序编码简单易懂
*效率低
(3).js是单线程还是多线程??
答:js的单线程运行的,因为开始js的业务比较简单,网速比较慢;
但使用H5中的Web Workers可以多线程运行;
(4).浏览器运行是单线程还是多线程??
答:都是多线程运行的 ;
2.浏览器内核
概念:浏览器也是一个软件应用,由许多程序代码组成,其中有一部分程序代码是它最核心的代码,我们把它称作内核;
1.浏览器内核是:支撑浏览器运行的最核心的程序。
2.不同的浏览器内核可能不一样。
3.js是单线程的
1.代码分类:
*初始化代码
*回调代码 (回调函数里面的代码就是回调代码)
2.js引擎执行代码的基本流程
(1)先执行初始化代码;
包括一些特别的代码:
*设置定时器
*绑定事件监听
*发送ajax请求
这些特殊代码初始化后,里面的回调函数代码会异步执行;
(2)后面某个时刻才会执行回调代码
3.在定时器中,定义定时器延迟时间
先初始化——》执行回调代码
若初始化时间 >延迟时间 :则初始化后执行代码
若初始化时间 <延迟时间 :则延迟时间后在执行
若初始化时间 =延迟时间 :则初始化后执行
即先初始化后,再执行,若初始化时间比较长,大于延迟时间,则执行代码的时间也会推迟。
<script type="text/javascript">
setTimeout(function(){
console.log("22222")
},2000);
setTimeout(function(){
console.log("11111");
alert("11111");
//alert弹窗暂停
},1000);
setTimeout(function(){
console.log("00000");
},0);
//虽然延迟为0,但是要先执行完初始化代码,再执行回调代码;
function fun(){
console.log("fun()");
}
fun();
console.log("alert()之前");
alert("------");
//alert暂停当前主线程的执行,同时暂停计时,
//点击确定后,恢复程序执行和计时
console.log("alert()之后");
//依次输出为fun()、alert()之前、弹窗alert("------");
//alert()之后、00000、11111 、弹窗alert("11111");
//22222
</script>
4.事件循环模型
1.所有代码分类
*初始化执行代码(同步代码):包含绑定dom事件监听,设置定时器,发送ajax请求的代码
(就是对他们先定义,不执行)
*回调执行代码(异步代码):处理回调逻辑
1.js引擎执行代码的基本流程:
*初始化代码——》回调代码
2.模型的2个重要组成部分:
*事件(定时器/DOM事件/ajax)管理模块
*回调队列
3.模型的运转流程
3.模型的运转流程:
(1)执行初始化代码,将事件定义的回调函数交给对应模块管理;
(2)当事件发生时,管理模块会将回调函数及其数据添加到回调队列中
(3)只有当初始化代码执行完后(可能需要一定时间)才会遍历读取队列中的回调函数执行;
相关重要概念
1.执行栈(execution stack)
:所有的代码都是再此空间中执行的; (即JS中的栈)
2.事件轮询(event loop)
:从任务队列中循环取出回调函数放入执行栈中处理(一个接着一个)
<script type="text/javascript">
function fun(){
console.log("fun()"); //初始化执行
}
fun();
var a=document.getElementById("a");
a.onclick=function(){
console.log("点击了按钮");
}
//初始化时,放在js管理引擎中,
//触发时放在队列中待执行,最后在js栈中执行
setTimeout(function(){
console.log("定时器执行了");
},2000);
//初始化时,放在js管理引擎中,
//初始化后时放在队列中待执行,最后在js栈中执行
function fun2(){
console.log("fun2()");
}
fun2();
</script>
5. H5 Web Workers(多线程)
1.介绍:
Web Workers 是HTMl5提供的一个JavaScript多线程解决方案。
我们可以将一些大计算量的代码交由Web Workers运行而不冻结用户界面
但是子线程完全受主线程控制,且不得操作DOM。
所以,这个新标准并没有改变你JavaScript单线程的本质
2.使用
*创建在分线程执行的js文件
*在主线程中的js中发消息并设置回调
3.不足:
*Worker内代码不能操作DOM(更新UI)
*不能跨越加载js
*不是每个浏览器都支持这个新特性
例题:实现一个数列规律: 1,1,2,3,5,8......(当前数字等于前两个数子之和) 则规律为:f(n)=f(n-1)+f(n-2);
则我们输入一个数(表示第几位),求该位置上的数字。
该题中,使用的递归调用,计算量比较大,
如果我们按js的单线程执行,则可能运算的时间比较长,而且在运算中,我们不能操作页面,所以用户的体验感很不好。
则使用h5的Web Workers
1.在分线程中:运算执行的结果,然后传递给主线程
function fi(n){ //传进去是第几位数字;
return n<=2?1:fi(n-1)+fi(n-2)
}
var onmessage =function (event){
var number=event.data;
console.log("分线程接收到主线程发送的数据"+number);
var result=fi(number);
//将接收到的数据传值进去计算;
postMessage(result);
//将计算结果返回;
console.log("分线程向主线程返回数据"+result);
}
2.在主线程中:不需要执行,直接拿到分线程中运算的结果即可。
则这样在主线程中就不需要等待,可以*操作页面
<input type="text" id="a" placeholder="数值"/>
<button id="b">点击计算</button>
<script type="text/javascript">
var a=document.getElementById("a"); //获取输入框标签
var b=document.getElementById("b"); //绑定按钮单击事件;
b.onclick=function(){
var number=a.value; //将输入框中的值number
//创建一个worker对象
var worker =new Worker("worker.js");//引入js文件
//向分线程发送信息,
worker.postMessage(number);
console.log("主线程向分线程发送数据"+number);
//绑定接收信息的监听
worker.onmessage=function (event){
console.log("主线程接收分线程返回的数据"+event.data);
alert(event.data);//事件对象event.data为接收的值
}
//绑定onmessage事件,即接收到分线程的信息就执行
}
//则这样之后,函数中计算量比较大的内容给分线程去做了,
//则在分线程计算的过程中,主线程同时可以与页面交互,操作页面;
console.log(this);//这个this代表window;;
</script>