JavaScript 事件循环机制

前言

我们知道 JavaScript 是单线程语言,也就是同一时间只能做一件事,这是因为 JavaScript 的主要作用是与用户互动以及操作 DOM ,如果是多线程的话,就会带来复杂的同步问题,比如:两个线程同时操作一个 DOM 节点,一个线程修改该节点,另一个线程删除该节点,此时就不知道该以哪个线程为准了。
但是单线程,又意味着任务需要排队等待,前一个任务执行完之后,后一个任务才会执行,这样就会导致一些执行很慢的任务会耽误大量的时间,于是 JavaScript 把所有的任务分成两种:同步任务、异步任务

同步任务和异步任务

  • 同步任务,指的是,在主线程上排队执行的任务,只有前一个任务执行完毕之后,后一个任务才会开始执行。
  • 异步任务,指的是,不进入主线程,而是进入任务队列,如果有多个任务,会在任务队列中排队等待,只有主线程的任务执行完毕之后,才会依次执行任务队列中的任务。

在了解同步任务异步任务的运行机制之前,我们先了解一下 执行栈、Event Table 以及 Event Queue 这几个名词

执行栈

我们知道,所有同步任务都在主线程执行,这样就形成来一个执行栈,也就是说,执行栈是一个存储函数调用的栈结构,主要负责跟踪所有要执行的代码

Event Table

Event Table 可以理解为是一张事件表格,存储的是异步任务中的事件以及其对应的回调函数列表,当异步任务有了结果,就会被丢到 Event Queue 中

Event Queue

Event Queue 就是所说的任务队列,当 Event Table 中的事件触发之后其对应的回调函数会被 push 到这个任务队列中,等待主线程任务完成后执行栈

那么,我们来看下其主要运行机制吧:
同步异步.png

  • JavaScript 代码执行时,将同步任务放入执行栈中,按顺序执行
  • 异步任务进入 Event Table 注册,当指定的事件完成时,Event Table 会将函数回调放入任务队列中,等待执行
  • 主线程任务执行完毕,会去 Event Queue 中取出完成的异步任务的回调放入主线程去执行
  • 不断重复上述过程,直至所有任务全部执行完毕,也就是我们所说的事件循环

到此,我们就了解了 JavaScript 中的同步任务和异步任务,但是我们的异步任务又可以分为两种:宏任务和微任务

宏任务和微任务

  • 宏任务:script (整体代码)、setTimeout 、 setInterval 、 I/O (Mouse Events、Keyboard Events)、UI交互事件
  • 微任务:Promise.then (非 new Promise)、 process.nextTick、

宏任务和微任务的区别在于队列中事件执行的优先级,微任务的优先级高于宏任务,也就是说,进入整体代码后,执行任务,当执行栈清空之后,会先查看有没有微任务,有微任务的话,会执行完所有的微任务之后,在执行一次宏任务,执行完之后,会再次检查有没有微任务,如此反复,直至所有任务都执行完毕。
宏任务微任务.png

由此我们可以简单的总结出来这个执行顺序:

  1. 同步任务执行
  2. 同步任务执行完毕,执行所有的微任务
  3. 读取任务队列中的一个宏任务执行
  4. 执行完宏任务之后,执行所有的微任务
  5. 再读取宏任务执行
  6. …如此反复,直至代码执行完毕

那么了解了这些之后,我们来看一道题:

console.log('1');

setTimeout(function() {
    
    
    console.log('2');
    process.nextTick(function() {
    
    
        console.log('3');
    })
    new Promise(function(resolve) {
    
    
        console.log('4');
        resolve();
    }).then(function() {
    
    
        console.log('5')
    })
})
process.nextTick(function() {
    
    
    console.log('6');
})
new Promise(function(resolve) {
    
    
    console.log('7');
    resolve();
}).then(function() {
    
    
    console.log('8')
})

setTimeout(function() {
    
    
    console.log('9');
    process.nextTick(function() {
    
    
        console.log('10');
    })
    new Promise(function(resolve) {
    
    
        console.log('11');
        resolve();
    }).then(function() {
    
    
        console.log('12')
    })
})

这里就不详细讲解这道题了,相信上面所说的都理解之后,这道题就很简单了。这里直接放出答案:1,7,6,8,2,4,3,5,9,11,10,12

扫描二维码关注公众号,回复: 14964925 查看本文章

猜你喜欢

转载自blog.csdn.net/gladysdrea/article/details/129422449