文章目录
进程与线程
进程
进程:程序的一次执行,它占有一片独有的内存空间可以,通过windows任务管理器查看进程
eg:
线程
是进程内一个独立执行的单元
是程序执行的一个完整流程
是CPU的最小调度单元
eg:
-
一个程序可以有多个进程
eg:chrome进程
-
单线程和多线程
单线程:一个进程中只有一个线程
多线程:一个进程中有多个线程
单线程和多线程局限在一个进程之内。
进程和线程之间的关系
- 应用程序必须运行在某个进程的某个线程上
- 一个进程中至少有一个运行的线程: 主线程,进程启动后自动创建
- 一个进程中也可以同时运行多个线程,我们会说程序是多线程运行的
- 一个进程内的数据可以供其中的多个线程直接共享
- 多个进程之间的数据是不能直接共享的(进程的内存是独立的)
- 线程池(thread pool):保存多个线程对象的容器,实现线程对象的反复利用
从线程池中拿出线程来执行程序,程序执行完成之后在将线程放回去。
可以这样简单理解进程与线程的关系:
- 进程:进程负责为程序的运行提供必备的环境——进程就相当于工厂中的车间
- 线程:线程计算机中的最小的计算单位,线程负责执行进程中的程序——线程就相当于工厂中的工人
相关问题
多进程与多线程
- 多进程运行:一应用程序可以同时启动多个实例运行
- 多线程:在一个进程内,同时有多个线程运行
单线程与多线程运行的区别
-
多线程:
优点:能有效提升CPU的利用率创建多线程开销
缺点:线程间切换开销、死锁与状态同步问题
单核的多线程是分时执行的,不同时刻执行不同的线程,所以会产生线程间切换开销 -
单线程
优点
:顺序编程简单易懂
缺点
:效率低
JS是单线程还是多线程
js是单线程运行的。——就一个主线程
问题:如果页面中一个地方加载运行,则整个页面都是卡死状态
解决:使用H5中的 Web Workers可以多线程运行。利用Web Workers产生分线程进行执行。
浏览器是单线程还是多线程
都是多线程运行的
浏览器是单进程还是多进程
有的是单进程:firefox、老版IE
有的是多进程:chrome、新版IE
浏览器内核
定义
浏览器内核是支撑浏览器运行的最核心的程序。
- 不同浏览器的内核是不一样的:
Chrome,Safari : webkit
firefox : Gecko
IE: Trident
360,搜狗等国内浏览器:Trident + webkit
组成内核的不同模块
主线程模块:
- js引擎模块∶负责js程序的编译与运行
- html,css文档解析模块:负责页面文本的解析
- DOM/CSS模块:负责dom/css在内存中的相关处理(将相关的标签转化成对象)
- 布局和渲染模块:负责页面的布局和效果的绘制(参照内存中的Dom对象)
分线程模块:
- 定时器模块:负责定时器的管理
- DOM事件响应模块:负责事件的管理
- 网络请求模块:负责ajax请求
定时器
定时器并不能保证真正定时执行。
一般会延迟一点点,这点延迟可以接受;但是若果有特殊情况,延迟很多的时候就不可以接受了。
- 延迟一点点:
<body>
<button id="btn">点击按钮启动定时器</button>
<script>
document.getElementById("btn").onclick = function () {
var start = Date.now();
console.log("定时器启动前");
setTimeout(function () {
console.log("定时器执行了", Date.now() - start);
}, 200);
console.log("定时器启动后");
};
</script>
</body>
- 延迟很多
<body>
<button id="btn">点击按钮启动定时器</button>
<script>
document.getElementById("btn").onclick = function () {
var start = Date.now();
console.log("定时器启动前");
setTimeout(function () {
console.log("定时器执行了", Date.now() - start);
}, 200);
console.log("定时器启动后");
for (var i = 0; i < 1000000000; i++) {
}
};
</script>
</body>
- 定时器在哪执行?
主线程执行,因为JS是单线程的只有一个主线程。 - 产生此现象的原因——事件循环模型
JS单线程执行的验证
alert
alert作用:会暂停主线程的执行,也会暂停计时器; 点击确定之后恢复程序执行和计时
代码:
<body>
<button id="btn">点击按钮启动定时器</button>
<script>
setTimeout(function (){
console.log('timeout 2222')
alert("22222222")
},2000)
setTimeout(function (){
console.log('timeout 1111')
alert("111111111")
},1000)
function fn (){
console.log('fn()')
}
console.log('alert之前')
// alert作用会暂停主线程的执行,也会暂停计时器
// 点击确定之后恢复程序执行和计时
alert("--------")
console.log('alert之后')
</script>
</body>
代码分类
- 初始化代码
- 回调代码
eg:
setTimeout(function (){
console.log('timeout 2222')
alert("22222222")
},2000)
setTimeout 属于初始化代码;
function (){
console.log(‘timeout 2222’)
alert(“22222222”)
} 属于回调代码
js引擎执行代码的基本流程
- 先执行初始化代码:包含一些特别的代码
- 设置定时器:绑定回调函数,但是不会执行回调函数
- 绑定dom事件监听:绑定回调函数,但是不会执行回调函数
- 发送ajax请求
- 后面在某个时刻才会执行回调代码——异步执行
eg:
setTimeout(function (){
console.log('timeout 2222')
},2000)
setTimeout(function (){
console.log('timeout 1111')
},1000)
setTimeout(function (){
console.log('timeout 0000')
},000)
function fn (){
console.log('fn()')
}
console.log('alert之前')
// alert作用会暂停主线程的执行,也会暂停计时器
// 点击确定之后恢复程序执行和计时
alert("--------")
console.log('alert之后')
输出顺序:
为什么js设置为单线程
如果有多个线程对一个DOM对象进行操作,可能会出现冲突。
事件循环模型
模型的2个重要组成部分:
- 事件(定时器/DOM事件/Aja)管理模块
- 回调队列(存放待处理的的回调函数)
模型原理图:
模型的运转流程:
- 执行初始化代码,将事件回调函数交给对应模块管理
- 当事件发生、到达时间点后,管理模块会将回调函数及其数据添加到回调列队中
- 只有当初始化代码执行完后(可能要一定时间),才会遍历读取回调队列中的回调函数执行
相关概念
执行栈
所有的代码都在此空间执行。
即:
浏览器内核
js引擎模块:在主线程处理
其它模块:在主/分线程处理
回调队列(callback queue)
又称为 任务队列、消息队列、事件队列
事件轮询 event loop
执行完初始化代码之后,需要从回调队列中循环取出回调函数放入执行栈中处理(一个接一个),该过程就成为事件轮询。
请求响应
H5 Web Workers(多线程)
单线程问题
当一个元素在计算原型,整个页面都不能操作。
eg:
<body>
<input type="text" name="" id="number" placeholder="数值">
<button id='btn'>计算</button>
<script>
function fibonacci(number){
// 1 1 2 3 5 8 13
return number<=2 ? 1:fibonacci(number-1)+fibonacci(number-2)
}
var input =document.getElementById('number')
document.getElementById('btn').onclick =function(){
var number = input.value
var result=fibonacci(number)
alert(result)
}
</script>
</body>
当输入一个较大的数字的时候,递归调用需要一定的时间,界面就处于加载的状态整个页面都不能操作。
WebWorks介绍
Web Workers是HTML5提供的一个javascript多线程解决方案
实现原理:
- 我们可以将一些大计算量的代码交由web Worker运行而不冻结用户界面
- 但是子线程完全受主线程控制,且不得操作DOM。(只有主线程测i能操作DOM)
所以,这个新标准并没有改变JavaScript单线程的本质
WebWorks使用
- 创建在分线程执行的js文件
- 在主线程中的js中发消息并设置回调
eg:
work.js文件
function fibonacci(number){
// 1 1 2 3 5 8 13
return number<=2 ? 1:fibonacci(number-1)+fibonacci(number-2)
}
var onmessage = function (event) {
var number = event.data
console.log("分线程接收到主线程发送的数据:" + number)
// 计算
var result = fibonacci(number)
postMessage(result)
console.log("分线程向主线程返回的数据:" + result)
}
.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<input type="text" name="" id="number" placeholder="数值">
<button id='btn'>计算</button>
<script>
var input =document.getElementById('number')
document.getElementById('btn').onclick =function(){
var number = input.value
// 创建一个worker对象,存放js文件
var worker = new Worker('./work.js')
// 向分线程发送消息
worker.postMessage(number)
console.log("主线程向分线程发送的数据:"+ number)
// 接收消息,注册监听
worker.onmessage = function (event){
console.log("主线程接收分线程返回的数据:"+event.data)
alert(event.data)
}
}
</script>
</body>
</html>
var worker = new Worker( 'worker.js ’ );
worker . onMessage = function(event){event.data}:用来接收另一个线程发送过来的数据的回调worker.postMessage(data) :向另一个线程发送数据
输出:
问题:JS文件的this是谁?
测试输出是DedicatedWorkerGlobalScope
,DedicatedWorkerGlobalScope
就是分线程的全局对象,onmessage、postMessage属性就在上面,可以直接调用该属性。
function fibonacci(number){
// 1 1 2 3 5 8 13
return number<=2 ? 1:fibonacci(number-1)+fibonacci(number-2)
}
console.log(this)
var onmessage = function (event) {
var number = event.data
console.log("分线程接收到主线程发送的数据:" + number)
// 计算
var result = fibonacci(number)
postMessage(result)
console.log("分线程向主线程返回的数据:" + result)
}
注意 :
alert是window的方法,分线程的全局对象不是window,自然不能调用alert了。
而 console是浏览器提供的谁都可以用。
所以由于分线程中的全局对象不再是window,所以在分线程中不可能更新界面(更新界面需要使用doument属性,而doument是window的属性,所以看不见)
图解
分线程的作用
解决一些费时间的计算
分线程缺点
慢(只是不阻塞主线程而已)
不能跨域加载JS
worker内代码不能访问DOM(更新UI)
不是每个浏览器都支持这个新特性