线程与进程
进程
- 程序的一次执行, 它占有一片独有的内存空间
- 可以通过windows任务管理器查看进程
线程
- 是进程内的一个独立执行单元
- 是程序执行的一个完整流程
- 是CPU的最小的调度单元
关系
- 一个进程至少有一个线程(主)
- 程序是在某个进程中的某个线程执行的
相关知识
- 应用程序必须运行在某个进程的某个线程上
- 一个进程中至少有一个运行的线程: 主线程, 进程启动后自动创建
- 一个进程中也可以同时运行多个线程, 我们会说程序是多线程运行的
- 一个进程内的数据可以供其中的多个线程直接共享
- 多个进程之间的数据是不能直接共享的
- 线程池(thread pool): 保存多个线程对象的容器, 实现线程对象的反复利用
相关问题
浏览器内核模块组成
支撑浏览器运行的最核心的程序
-
主线程
- js引擎模块 : 负责js程序的编译与运行
- html,css文档解析模块 : 负责页面文本的解析
- DOM/CSS模块 : 负责dom/css在内存中的相关处理
- 布局和渲染模块 : 负责页面的布局和效果的绘制(内存中的对象)
-
分线程
- 定时器模块 : 负责定时器的管理
- DOM事件模块 : 负责事件的管理
- 网络请求模块 : 负责Ajax请求
js线程
-
如何证明js执行是单线程的?
- setTimeout()的回调函数是在主线程执行的
- 定时器回调函数只有在运行栈中的代码全部执行完后才有可能执行
-
为什么js要用单线程模式, 而不用多线程模式?
- JavaScript的单线程,与它的用途有关。
- 作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。
- 这决定了它只能是单线程,否则会带来很复杂的同步问题—设置互斥只允许一个线程操作
-
代码的分类:
- 初始化代码
- 回调代码
-
js引擎执行代码的基本流程
-
先执行初始化代码: 包含一些特别的代码
- 设置定时器
- 绑定监听
- 发送ajax请求
-
后面在某个时刻才会执行回调代码
-
- js是单线程执行的(回调函数也是在主线程)
- H5提出了实现多线程的方案: Web Workers
- 只能是主线程更新界面
定时器问题
-
定时器真是定时执行的吗?
- 定时器并不能保证真正定时执行
- 一般会延迟一丁点(可以接受), 也有可能延迟很长时间(不能接受)(如果在主线程执行了一个长时间的操作, 可能导致延时才处理)
-
定时器回调函数是在分线程执行的吗?
- 在主线程执行的, js是单线程的
-
定时器是如何实现的?
-
事件循环模型(后面讲)
-
事件处理机制
所有代码分类
- 初始化执行代码: 包含绑定dom事件监听, 设置定时器, 发送ajax请求的代码
- 回调执行代码: 处理回调逻辑
js引擎执行代码的基本流程:
- 初始化代码===>回调代码
模型的2个重要组成部分:
- 事件管理模块
- 回调队列
模型的运转流程
- 执行初始化代码, 将事件回调函数交给对应模块管理
- 当事件发生时, 管理模块会将回调函数及其数据添加到回调列队中
- 只有当初始化代码执行完后(可能要一定时间), 才会遍历读取回调队列中的回调函数执行
相关重要概念
H5 Web Workers
介绍
- Web Workers 是 HTML5 提供的一个javascript多线程解决方案
- 我们可以将一些大计算量的代码交由web Worker运行而不冻结用户界面
- 但是子线程完全受主线程控制,且不得操作DOM。所以这个新标准并没有改变JS单线程的本质
使用
- 创建在分线程执行的js文件
//worker.js
var onmessage =function (event){ //不能用函数声明
var upper= event.data;//通过event.data获得发送来的数据
var result=upper.toUpperCase(); //处理主线程传过来的数据并返回给主线程
postMessage( result);//将获取到的数据发送会主线程
}
- 在主线程中的js中发消息并设置回调
//创建一个Worker对象并向它传递将在新线程中执行的脚本的URL
var worker = new Worker("worker.js");
//接收worker传过来的已处理的数据
worker.onmessage = function (event) {
console.log(event.data); //HELLO WORLD
};
//向worker发送数据
worker.postMessage("hello world");
应用练习
编程实现斐波那契数列(Fibonacci sequence)的计算F(0)=0,F(1)=1,..... F(n)=F(n-1)+F(n-2)
-
直接在主线程
响应慢,影响了页面的操作
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)
- 打印分线程的this
- 分线程中的全局对象不在是window,所以在分线程中无法更新界面,无法使用window的方法,比如alert
-
不是每个浏览器都支持这个新特性