线性机制与事件机制
210318-20
1、进程与线程
-
进程(process):
- 程序的一次执行,它占有一片独有的内存空间
- 可以通过Windows任务管理器查看进程
-
线程(thread):
- 是进程内的一个独立执行单元
- 是程序执行的一个完整流程
- 是CPU的最小的调度单元
-
图解
-
相关知识
- 应用程序必须运行在某个进程的某个线程上
- 一个进程中至少有一个运行的线程:主线程,进程启动后自动创建
- 一个进程中也可以同时运行多个线程,会说程序是多线程运行的
- 一个进程内的数据可以供其中的多个线程直接共享
- 多个进程之间的数据是不能直接共享的
- 线程池(thread pool):保存多个线程对象的容器,实现线程对象的反复利用
-
相关问题
- 何为多进程与多线程?
- 多进程运行:一个应用程序可以同时启动多个线程运行
- 多线程:在一个进程内,同时有多个线程运行
- 比较单线程与多线程?
- 多线程
- 优点:能有效提升CPU的利用率
- 缺点:创建多线程开销、线程间切换开销(单核多线程,跳转运行),死锁与状态同步问题
- 单线程
- 优点:顺序编程简单易懂
- 缺点:效率低
- 多线程
- js是单线程还是多线程?
- js是单线程运行的
- 但使用h5中的web workers可以多线程运行
- 浏览器运行时单线程还是多线程?
- 都是多线程运行的
- 浏览器运行是单进程还是多进程?
- 有的是单进程:firefox,老版IE
- 有的是多进程:chrome,新版IE
- 如何查看浏览器是否是多进程运行的:Windows任务管理器
- 何为多进程与多线程?
2、浏览器内核
- 支持浏览器运行的最核心的程序
- 不同浏览器可能不一样
- chrome:blink
- safari:webkit
- firefox:Gecko
- IE:trident
- 360、搜狗等国内浏览器:trident(安全性高点)+webkit(双核双驱动)
- 内核由很多模块组成
- 主线程
- js引擎模块:负责js程序的编译与运行
- html,css文档解析模块:负责页面文本的解析
- DOM/CSS模块:负责dom/css在内存中的相关处理
- 布局和渲染模块:负责页面的布局和效果的绘制(内存中的对象)
- 分线程
- 定时器模块:负责定时器的管理
- DOM事件模块:负责事件的管理(异步)
- 网络请求模块:负责ajax请求
- 主线程
3、定时器引发的思考
- 定时器并不能保持真正定时执行
- 一般会延迟一点(可以接受),也有可能延迟很长时间
- 定时器回调函数在主线程执行的,js是单线程的
- 定时器的实现是事件循环模型
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++){
}
}
<button id="btn"></button>
4、js是单线程执行的
- 如何证明js执行是单线程?
- setTimeout()的回调函数是主线程执行的
- 定时器回调函数只有在运行栈中的代码全部执行完后才有可能执行
- 为什么js要用单线程模式,而不是多线程模式?
- javascript的单线程,与它的用途有关
- 作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM(多个用户操作同一个对象是,只能是一个接一个操作,只有一个线程更新操作界面)
- 这决定了他只能是单线程,否则会带来很复杂的同步问题
- 代码分类:
- 初始化代码:包括绑定DOM时间监听,设置定时器,发送ajax请求代码
- 回调代码:处理回调逻辑
- js引擎执行代码的基本流程(初始化代码-->回调代码)
- 先执行初始化代码:包含一些特别的代码 回调函数(异步执行)
- 设置定时器
- 绑定事件监听
- 发送ajax请求
- 后面在某个时刻才会执行回调函数
- 先执行初始化代码:包含一些特别的代码 回调函数(异步执行)
setTimeout(function(){
console.log('222222')
},2000)
setTimeout(function(){
console.log('11111')
},1000)
setTimeout(function(){
console.log('00000')
},0)
function fn(){
console.log('fn()')
}
fn()
console.log('alert()之前')
alert('-------') //暂停当前主线程的执行,同时暂停计时,点击确定后,恢复程序执行和计时
console.log('alert()之后')
5、浏览器的事件循环(轮询)模型
模型的运转流程
- 执行初始化代码,将事件回调函数交给对应模块管理
- 当事件发生时,管理模块会将回到函数及其数据添加到回调队列中
- 只有当初始化代码执行完后(可能要一定时间),才会遍历读取回调队列中的回调函数执行
- 执行栈
- execution stack
- 所有的代码都是在此空间中执行的
- 浏览器内核
- browser core
- js引擎模块(在主线程处理)
- 其他模块(在主/分线程处理)
- 同一个:callback queue
- 任务队列:task queue
- 消息队列:message queue
- 事件队列:event queue
- 事件轮询
- event loop
- 从任务队列中循环取出回调函数放入执行栈中处理(一个接一个)
- 事件驱动模式
- event-driven interaction model
- 请求响应模型
- request-response model
6、H5 Web Workers(多线程)
- 介绍
- h5规范提供了js多线程的实现(解决方案),取名:web workers
- 可以将一些大计算量的代码交由web worker运行而不冻结用户界面
- 但是子线程完全受主线程控制,且不得操作DOM(分线程中this不是window对象)。所有,这个新标准并没有改变JavaScript单线程的本质
- 只有主线程更新界面
-
使用
- 创建在分线程执行的js文件
- 在主线程中的js中发消息并设置回调
//web workers测试.html中 var input = document.getElementById("number") document.getElementById('btn').onclick = function(){ var number = input.value //创建一个worker对象并向它传递将在新线程中执行的脚本的URL var worker = new Worker('worker.js') //绑定接收消息的监听,接收worker传过来的数据函数 worker.onmessage = function(event){ console.log("主线程接收分线程返回的数据:"+event.data) alert(event.data) } //向分线程发送消息 worker.postMessage(number) console.log('主线程向分线程发送数据:'+number) } /*创建在分线程执行的js文件worker.js*/ function fibonacci(n){ return n<=2 ? 1 : fibonacci(n-1) + fibonacci(n-2)//递归调用 } var onmessage = function(event){//不能函数声明 var number = event.data console.log('分线程接收到主线程发送的数据:'+number); var result = fibonacci(number) postMessage(result); console.log('分线程向主线程返回数据:'+result); } console.log(this) //不是window,不能使用window的方法alert //分线程中的全局对象不再是window,所以在分线程中不可能更新界面
-
图解
-
相关api
- Worker:构造函数,加载分线程执行的js文件
- Worker.prototype.onmessage:用于接收另一个线程的回调函数
- Worker.prototype.postMessage:向另一个线程发送消息
-
不足
- 慢
- worker内代码不能操作DOM(更新UI)(全局对象不再是window)
- 不能跨域加载js
- 不是每个浏览器都支持这个新特性