浅谈js的事件循环(Event Loop)

  • 事件循环是js这门语言的一大特色。
  • 了解事件循环机制,有助于平常开发中遇到的一些异步问题。
  • 并且仍是前端面试一常常考点。
  • 故本人结合一些文章和我的的一些开发经验,浅淡一下

一,js是一门单线程语言

  1. js的单线程
a. js是一门单线程的语言。这意味着它在同一时间,只能作同一件事。
b. 但为了协调事件,用户交互,UI渲染和网络行为交互等。
c. 防止主线程被阻塞,Event Loop便应运而生。
如: 发送一个网络请求,须要等待必定时间,这个时间内主线程空闲出来作些其余事;
复制代码
  1. 为何js是单线程?
a. js主要是运行在浏览器的脚步语言,主要是操做dom;
b. 举个例子,若是js同时有多个线程。多个线程同时操做同一个dom,
   这时浏览器该依据那个线程,如何判断优先级
c. 为了不上述问题,并下降复杂度,故js被设计成单线程语言。
复制代码

二,概念的理解

  1. 同步任务
同步任务指的是,在主线程上排队执行的任务,
只有前一个任务执行完毕,才能执行后一个任务;
复制代码
  1. 异步任务
异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,
只有"任务队列"通知主线程,某个异步任务能够执行了,该任务才会进入主线程执行。
复制代码
  1. 异步执行机制
a. 全部同步任务都在主线程上执行,造成一个执行栈(execution context stack);
b. 主线程以外,还存在一个"任务队列"(task queue)。
   只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
c. 一旦"执行栈"中的全部同步任务执行完毕,系统就会读取"任务队列",
   看看里面有哪些事件。那些对应的异步任务,因而结束等待状态,
   进入执行栈,开始执行。
d. 主线程不断重复上面的第三步。
复制代码
  1. 任务队列
"任务队列"是一个先进先出的数据结构,排在前面的事件,优先被主线程读取。
复制代码
  1. 事件循环
主线程从"任务队列"中读取事件,这个过程是循环不断的,
因此整个的这种运行机制又称为Event Loop(事件循环)。
复制代码
  1. 宏任务与微任务
异步任务分为 宏任务(macrotask) 与 微任务 (microtask),
不一样的API注册的任务会依次进入自身对应的队列中,
而后等待 Event Loop 将它们依次压入执行栈中执行。

宏任务:script(总体代码)、setTimeout、setInterval、UI 渲染、 
        I/O、postMessage、 MessageChannel、setImmediate(Node.js 环境)
        
微任务:Promise、 MutaionObserver、process.nextTick(Node.js环境)
复制代码
  1. Event Loop(事件循环)
1)执行栈选择最早进入队列的宏任务(一般是script总体代码),若是有则执行;
(2)检查是否存在 Microtask,若是存在则不停的执行,直至清空 microtask 队列;
(3)更新render(每一次事件循环,浏览器均可能会去更新渲染);
(4)重复以上步骤;
复制代码
  1. 宏任务 > 全部微任务(核心),上代码
<script>// 宏任务1
    console.log('宏任务1'); // 宏任务1中的同步任务
    
    setTimeout(() => {// 宏任务1中的另外一个宏任务3
        console.log('宏任务1中的另外一个宏任务3');
        
        new Promise((resolve, reject) => {
            resolve('宏任务3中的微任务2');
        }).then(data => {// 宏任务3中的微任务2
            console.log(data)
        })
        
    }, 300);
    
    new Promise((resolve, reject) => {
        resolve('宏任务1中的微任务1');
    }).then(data => {// 宏任务1中的微任务1
        console.log(data);
        
        setTimeout(() => {// 微任务1中的另外一个宏任务4
            console.log('微任务1中的另外一个宏任务4');
        }, 300);
        
    });
    
</script>// 宏任务1

<script>// 宏任务2
    console.log('宏任务2')
</script>// 宏任务2
复制代码
  • 上述代码的执行结果

  • 代码结果分析:
1. 宏任务1=>宏任务1中的微任务1
   代表执行完宏任务就执行微任务(忽略宏任务2,便于理解)
2. 而后到 宏任务1中宏任务3=>宏任务3中的微任务2
   再次代表执行完本宏任务后就执行本宏任务下的微任务
3. 最后到微任务1中的宏任务4
复制代码
相关文章
相关标签/搜索