浏览器的进程
- 进程是计算机调度的基本单位,进程中包含着线程,每一个页签都是一个进程,互不影响;
- 浏览器也有一个主线程 (用户界面);
- 渲染进程:每个页签里都有一个渲染进程 (浏览器内核);
- 网路进程 (处理请求);
- GPU 进程,3d 绘制;
- 第三方插件的进程;
渲染进程(包含多个线程)
GUI 渲染进程(渲染页面);
js 引擎线程与页面渲染时互斥;
事件触发线程是独立的线程 EventLoop;
事件 click、setTimeout、ajax 也是一个独立的线程;
异步任务
语言标准提供的异步方法一般都是 微任务;
宿主环境提供的异步方法一般都是 宏任务;
微任务
-
promise.then
-
process.nextTick (有可能是宏任务)
-
MutationObserver 监视 DOM 变动
宏任务
-
ui 渲染 (优先级较高)
-
requestAnimationFrame (优先级较高,具体情况需要根据 屏幕的刷新频率 来判断)
-
script 脚本
-
ajax
-
事件函数
-
setTimeout
-
setInterval
-
setImmediate
-
…
事件循环图解
案例分析
<body>
<script>
document.body.style.background = 'green';
console.log(1);
Promise.resolve().then(() => {
console.log(2);
document.body.style.background = 'red';
});
console.log(3);
// 1 3 2 red(只渲染红色)
</script>
</body>
<body>
<script>
document.body.style.background = 'green';
console.log(1);
setTimeout(() => {
console.log(2);
document.body.style.background = 'red';
}, 10);
console.log(3);
// 1 3 2 green => red(屏幕闪烁)
</script>
</body>
面试题
第 1 题
-
题目
let n = 0; // 设置定时器的操作是同步的,但是 1S 后做的事情是异步的 setTimeout(_ => { n += 10; console.log(n); }, 1000); n += 5; console.log(n);
-
图解
第 2 题
-
题目
setTimeout(() => { console.log(1); }, 20); console.log(2); setTimeout(() => { console.log(3); }, 10); console.log(4); // 计时开始 console.time('AA'); for (let i = 0; i < 90000000; i++) { // do soming 280ms左右 } // 计时结束 console.timeEnd('AA'); console.log(5); setTimeout(() => { console.log(6); }, 8); console.log(7); setTimeout(() => { console.log(8); }, 15); console.log(9);
-
图解
第 3 题
console.log(1);
setTimeout(_ => console.log(2), 50);
console.log(3);
setTimeout(_ => {
console.log(4);
// 遇到死循环,所有代码执行最后都是在主栈中执行,遇到死循环,主栈永远结束不了,后面啥都干不了
while (1 === 1) { }
}, 0);
console.log(5);
第 4 题
<body>
<button id="button">按钮</button>
<script>
button.addEventListener('click', () => {
console.log('listener1');
Promise.resolve().then(() => console.log('micro task1'))
})
button.addEventListener('click', () => {
console.log('listener2');
Promise.resolve().then(() => console.log('micro task2'))
})
button.click(); // 相当于函数执行 click1() click2(),此时并未将回调放到 宏任务队列中
// listener1
// listener2
// micro task1
// micro task2
</script>
</body>
<body>
<!-- 点击按钮 -->
<button id="button">按钮</button>
<script>
button.addEventListener('click', () => {
console.log('listener1');
Promise.resolve().then(() => console.log('micro task1'))
})
button.addEventListener('click', () => {
console.log('listener2');
Promise.resolve().then(() => console.log('micro task2'))
})
// 点击按钮执行事件,将两个事件回调都放到了宏任务队列中,每次拿出一个执行
// listener1
// micro task1
// listener2
// micro task2
</script>
</body>
第 3️⃣ 座大山:浏览器的渲染机制、重绘、回流
上一篇