@[TOC]
线程机制与事件机制
进程与线程
1. 进程(process):
程序的一次执行,它占有一片独有的内存空间 可以通过windows任务管理器查看进程
2. 线程(thread):
是进程内的一个独立执行单位 是程序执行的一个完整流程 是CPU的最小的调度单元
3. 图解
4. 相关知识:
应用程序必须运行在某个进程的某个线程上 一个进程中一般至少有一个运行的线程:主线程,进程启动后自动创建 一个进程中也可以同时运行多个线程,我们会说程序是多线程运行的 一个进程内的数据可以供其中的多个线程直接共享 多个线程之间的数据是不能直接共享的 ==线程池(thread pool)==: 保存多个线程对象的容器, 实现线程对象的反复利用
5.相关问题
何为多线程?
多进程运行: 一应用程序可以同时启动多个实例运行 多线程: 在一个进程内, 同时有多个线程运行
比较单线程与多线程?
多线程:
优点:
- 能有效提升CPU效率
缺点:
- 创建爱你多线程开销
- 线程切换开销 死锁与状态同步问题
JS单线程还是多线程?
js是单线程运行的 但使用H5中的 Web Workers可以多线程运行
浏览器运行是单线程还是多线程?
都是多线程
浏览器运行是单进程还是多进程?
有的是单线程
- 老版火狐firefox(2017年以前)
- 老版IE
有的是多线程
- chrome
- 新版IE
如何查看浏览器是否是多进程运行的呢?
- 任务管理器-->进程
浏览器内核
1. 支撑浏览器运行的最核心的程序
2. 不同的浏览器可能不一样
Chrome,Safari:webkit firefox:Gecko IE:Trident 360,搜狗等多内浏览器:Trident + webkit
3. 内核由很多模块组成
主线程:
js引擎模块 : 负责js程序的编译与运行 html,css文档解析模块 : 负责页面文本的解析 DOM/CSS模块 : 负责dom/css在内存中的相关处理 布局和渲染模块 : 负责页面的布局和效果的绘制(内存中的对象) ....
分线程:
定时器模块 : 负责定时器的管理 DOM事件响应模块 : 负责事件的管理 网络请求模块 : 负责ajax请求
定时器引发的思考
1. 定时器真是定时执行的吗?
定时器并不能保证真正定时执行 一般会延迟一丁点(可以接受),也有可能延迟很长时间(不能接受)
2. 定时器回调函数是在那个线程执行的?
在主线程执行的,js是单线程的
3. 定时器是如何实现的?
事件循环模型(后面讲)
JS是单线程执行的
- 如何证明js执行是单线程的?
- 为什么js要用单线程模式,而不用多线程模式?
- 代码的分类
- js引擎执行代码的基本流程
document.querySelector("button").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++) {}
};
JS是单线程的
1. 如何证明js执行是单线程的?
setTimeout()的对调函数是在主线程执行的 定时器回调函数只有在运行栈中的代码全部执行完后才有可能执行
2. 为什么js要用单线程模式,而不用多线程模式?
JavaSctiptde 的单线程,与它的用途有关 作为浏览器脚本语言,JavaSctipt的主要用途是与用户互动,以及操作DOM 这决定了它只能是单线程,否则会带来很复杂的同步问题
3. 代码分类:
初始化代码 回调函数
4. js引擎执行代码:包含一些特别的代码
先执行初始化代码:包含一些特别的代码
- 设置定时器
- 绑定监听
- 发送ajax请求 后面在某个时刻才会执行回调函数代码
事件循环模型
1. 所有代码分类
初始化执行代码(同步代码):包含绑定dom事件监听,设置定时器,发送ajax请求的代码 回调执行代码(异步代码):处理回调逻辑
2. js引擎执行代码的基本流程:
初始化代码===>回调代码
3. 模型的2个重要组成部分:
事件管理模块 回调队列
4. 模型的运转流程
执行初始化代码,将事件回调函数交给对应模块管理 当事件发生时,管理模块会将回调函数及其数据添加到回调函数列队中 只有当初始化代码执行完后(可能要一定的时间),才会遍历读取调队列中的回调函数执行
插入:浏览器的时间虚循环(轮询)模型:
模型原理图
相关重要概念
- 执行栈
execution stack 所有代码都是此空间中执行的
- 浏览器内核
browser core js引擎块(在主线程处理) 其他模块(在主/分线程处理)
- 任务队列
task queue
- 消息队列
message queue
- 时间队列
event queue
- 事件轮询
event loop 从任务队列中循环取出回调函数放入执行栈中处理(一个接一个)
- 事件驱动模型
event-driven interaction model
- 请求响应模型
request-response model
Web Workers_测试
1. H5规范提供了js分线程的实现,取名为:Web Workers
2. 相关API
Worker:构造函数,加载分线程执行的js文件 Worker.prototype.onmessage:用于接受另一个线程的回调函数 Worker.prototype.postMessage:向另一个线程发送消息
3. 不足
worker内代码不能操作DOM(更新UI) 不能跨域加载JS 不是每个浏览器都支持这个新特性
var input = document.querySelector("input");
document.querySelector("button").addEventListener("click", function () {
var number = input.value;
function fibonacci(n) {
// 1 1 2 3 5 8 13 21 34 55 89 f(n) = f(n-1)+f(n-2)
return n <= 2 ? 1 : fibonacci(n - 1) + fibonacci(n - 2); // 递归调用
}
console.log(fibonacci(number));
});
插入H5 Web Workers(多线程)
介绍
Web Workers 是HTML5提供的一个javascript多线程解决方案 我们可以将一些大计算量的代码交由web Worker运行而不冻结用户界面 但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质
使用
创建在分线程执行的js文件 在主线程中的js中发消息并设置回调
图解
应用练习
直接在主线程
var fibonacci =function(n) {
return n <2 ? n : fibonacci(n -1) + fibonacci(n -2);
};
console.log(fibonacci(48));
使用Worker在分线程
- 主线程
var worker = new Worker('worker2.js');
worker.addEventListener('message', function (event) {
var timer2 = new Date().getTime();
console.log('结果:' + event.data, '时间:' + timer2, '用时:' + ( timer2 - timer ));
}, false);
var timer = new Date().getTime();
console.log('开始计算: ', '时间:' + timer);
setTimeout(function () {
console.log('定时器函数在计算数列时执行了', '时间:' + new Date().getTime());
}, 1000);
worker.postMessage(40);
console.log('我在计算数列的时候执行了', '时间:' + new Date().getTime());
- 分线程
var fibonacci =function(n) {
return n <2 ? n : fibonacci(n -1) + fibonacci(n -2);
};
var onmessage = function(event) {
var n = parseInt(event.data, 10);
postMessage(fibonacci(n));
};
不足
- 慢
- 不能跨域加载JS
- worker内代码不能访问DOM(更新UI)
- 不是每个浏览器都支持这个新特性