一、浏览器的进程和线程
前端研发人员不要忘记了浏览器是安装在PC电脑(手机)上的应用。既然是客户端应用,就免不了一个问题:线程和进程。
- 一个程序可以有多个进程;
- 一个进程和多个线程;
- 多个进程之间可以相互通信;
- 多个线程之间可以相互通信;
- 不同进程之间的线程不能相互通信。
好,知道了这些基本的知识,我们来看一下浏览器(以谷歌浏览器为例)这个最基本的应用程序有哪些进程,又有哪些线程。
Chrome的进程:大家可以打开任务管理器看看,有哪些进程
从图中可以看到,在chrome中每打开一个标签页,每一个扩展程序都是一个进程。
Chrome的线程:对于一个进程来说,又有哪些线程呢?
- GUI 渲染线程
- JavaScript引擎线程
- 定时触发器线程
- 事件触发线程
- 异步http请求线程
那么当你打开一个页面,就启动了一个进程,那么这个进程有上面几个线程。这几个线程之间相互合作,但是GUI和JavaScript之间是相互独立的,而且Javascript是单线程的。原因很简单,涉及UI操作的不能同时处理,不然给用户呈现的页面会是什么样子。
既然知道了,浏览器作为应用程序具备的基本要素。那么我们想看看浏览器内部具体的工作方式。
了解一个程序,首先了解程序的模块划分和工作流程。
浏览器主要划分这几个模块浏览器部件:那么这几个部件相互耦合,为用户提供页面。
- 1、用户界面
- 2、浏览器引擎
- 3、渲染引擎
- 4、网络
- 5、用户界面后端
- 6、Javascript解释器
- 7、数据持久化存储
二、浏览器页面渲染的方式(页面初始化)
我们重点来看一下浏览器的渲染是怎么操作的
三、浏览器的事件系统(页面操作)Macro和Micro
异步并不是不执行,而是执行放入队列。
四、案例(可能是你们最想看的)
//案例一:
setTimeout(() => {
console.log(promise);
console.log('settimeout1');
}, 0);
let promise = new Promise(function(resolve, reject) {
console.log('Promise');
setTimeout(()=>{
resolve('success');
},0);
//resolve('success');
}).then((msg)=>{
console.log('resolved.'+msg);
});
setTimeout(() => {
console.log(promise);
console.log('settimeout2');
}, 0);
console.log(promise);
console.log('Hi!');
//输出结果
Promise //Promise会立即执行
Promise { <pending> } //此时promise状态为pending
Hi! //打印hi
Promise { <pending> }
settimeout1 //主线程执行完毕,依次将三个settimeout放入macro队列中,打印第一个
Promise { <pending> }
settimeout2 //打印第二个
resolved.success //promise执行成功
//案例二:
如果promise中直接resolve('success'),运行结果是怎么样?
Promise
Promise { <pending> }
Hi!
resolved.success
Promise { undefined }
settimeout1
Promise { undefined }
settimeout2
//案例三:
如果在React中的事件系统是什么样子的呢?
class Father extends Component {
render() {
let promise = new Promise(function(resolve, reject) {
resolve('success1');
}).then((msg)=>{
console.log('resolved.'+msg);
});
return (
<Son ref="son"/>
);
}
componentDidMount(){
console.log('Did Mount');
}
componentWillMount(){
let promise = new Promise(function(resolve, reject) {
resolve('success2');
}).then((msg)=>{
console.log('resolved.'+msg);
});
console.log('Will Mount');
}
}
//输出结果
Will Mount
Did Mount
resolved.success2
resolved.success1
可以看到react并没有将micro任务合并到渲染里面
为什么会提及React,因为React 的处理方式和我们和浏览器的实现流程比较类似。
React初始化《======》浏览器初始加载
React更新 《======》浏览器的事件系统
所以React从很大程度上做了一层抽象,让我们面向组件的函数编程,而不是面向浏览器的编程。
附录:Node中的事件系统Node
node环境中的事件系统多了两个 process.nextTick和setImmediate
//案例四:
setTimeout(() => {
console.log(promise);
console.log('settimeout1');
}, 0);
let promise = new Promise(function(resolve, reject) {
console.log('Promise');
/*setTimeout(()=>{
resolve('success');
},0);*/
resolve('success');
}).then((msg)=>{
console.log('resolved.'+msg);
});
setTimeout(() => {
console.log(promise);
console.log('settimeout2');
}, 0);
console.log(promise);
console.log('Hi!');
process.nextTick(()=>{console.log('nextTick')});
setImmediate(()=>{console.log('Immediate')}) ;
//输出结果
Promise
Promise { <pending> }
Hi!
nextTick
resolved.success
Promise { undefined }
settimeout1
Promise { undefined }
settimeout2
Immediate