Skip to content

浏览器事件循环 ​

本节目标:理解“浏览器事件循环”的核心思路,并能把它用于实际开发或面试表达。

说明:原 OneNote 中有图片引用,但图片未包含在导出目录中;本页保留了可用的文字与代码内容。 事件环为了实现js的异步概念

js是“单线程” (主线程)的, 我们在写代码的时候 setTimeout ajax

进程:计算机分配任务的最小单位 (不是按照线程分配的) 进程里包含多个线程

浏览器是由多个进程组成的

EventLoop解决的是 js执行时可能会调用异步方法,这些方法是怎样调度执行的

  1. js执行的时候 会从上到下执行,遇到函数会创建执行上下文放入到执行栈中,执行完毕后会出栈 执行时可能会发生异步事件--\>内部会调用浏览器Api
  2. 当我们执行上下文栈都执行完毕后, 等会可能api执行完成或者时间到达,会被我IE互道一个事件“队列”、消息“队列”;
  3. 不停的扫描队列,将队列里的任务拿出来放到上下文栈中执行:事件循环线程是专门干这件事的,检测当前执行栈是否为空,如果为空,从事件队列中取出一个来执行 setTimeout 宏任务;
  4. 当代码执行时还会有一些任务,promise为例,微任务,每次执行宏任务的时候 都会单独创建一个微任务“队列”;
  5. 微任务在执行完毕后,浏览器会检测是否要重新渲染,浏览器有刷新频率大约16.6ms;
  6. 每次循环一次都会执行一个宏任务,并清空对应的微任务队列,每次循环完毕后,都要看是否要渲染,如果需要渲染才渲染;

宏任务有哪些:

  • script脚本
  • 界面渲染也是宏任务
  • setTimeout setInterval;
  • postMessage;
  • MessageChannel;
  • Node中的setImmediate
  • 事件 ajax

微任务有哪些:

  • promise.then
  • mutationObserver
Node 中的 Process.nextTick等

微任务中在执行时再生成微任务,会在本轮直接清空 console.log('abc') // [s1

,s2]
setTimeout(()

=\> {

console.log('abc');
},
1000);
setTimeout(()

=\> {

console.log('bcd');
},

500);

1.浏览器的进程

  • 每一个页卡都是进程 (互不影响)
  • 浏览器也有一个主进程 (用户界面)
  • 渲染进程 每个页卡里 都有一个渲染进程 (浏览器内核)
  • 网络进程 (处理请求)
  • GPU进程 3d绘制
  • 第三方插件的进程

2. 渲染进程(包含着多个线程)

  • GUI渲染线程 (渲染页面的)
  • js引擎线程和页面渲染线程是互斥的;
  • 事件触发线程:独立的线程 EventLoop
  • 事件线程也是一个独立的线程,如:click、setTimeout、ajax
# 3.

宏任务,微任务

  • 宏任务 宿主环境提供的异步方法 都是宏任务 script ui 渲染
  • 微任务 语言标准提供promise mutationObserver
# 4.

微任务和GUI渲染

<script>        document.body.style.background = 'red';        console.log(1)        Promise.resolve().then(()=>{            console.log(2)            document.body.style.background = 'yellow';        })        console.log(3);</script>
# 5.

事件任务

<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()</script>
# 6.

定时器任务

<script>        Promise.resolve().then(() => {            console.log('Promise1')            setTimeout(() => {                console.log('setTimeout2')            }, 0);        })        setTimeout(() => {            console.log('setTimeout1');            Promise.resolve().then(() => {                console.log('Promise2')            })        }, 0);</script>
# 7.

任务执行面试题

console.log(1);async function async () {    console.log(2);    await console.log(3);    console.log(4)}setTimeout(() => {	console.log(5);}, 0);const promise = new Promise((resolve, reject) => {    console.log(6);    resolve(7)})promise.then(res => {	console.log(res)})async (); console.log(8);

掌握Vue中nextTick原理

宏任务每执行一个,微任务队列清空; 宏任务队列只有一个,微任队列只有一个,但会多次清空;清空后再加入新任务,相当于多个微任务队列一样;

当执行栈中的同步任务执行完后,就会去任务队列中拿一个宏任务放到执行栈中执行,执行完该宏任务中的所有微任务,再到任务队列中拿宏任务,即一个宏任务、所有微任务、渲染、一个宏任务、所有微任务、渲染...(不是所有微任务之后都会执行渲染),如此形成循环,即事件循环(EventLoop)

但浏览器特殊的规定,如果promise 返回了一个promise,会额外再开辟一个异步方法(相当于又多了一次then)

重看promsie 解题 4/4号

> 来自

 <http://www.zhufengpeixun.com/jg-vue/node/async-2.html#_6-%E5%AE%9A%E6%97%B6%E5%99%A8%E4%BB%BB%E5%8A%A1>

本站总访问 — 次