Event Loop/事件循环/JS的运行机制

在JavaScript中,有两种任务:
宏任务(MacroTask)

  • script(整体代码)、
  • setTimeout、
  • setInterval、
  • setImmediate(浏览器暂时不支持,只有IE10支持)、
  • I/O、
  • UI Rendering
    微任务(MicroTask)
  • process.nextTick(node独有)、
  • Promise、
  • Async/Await(实际就是promise)、
  • MutationObserver(html5新特性)
image.png
  • 同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数。
  • 当指定的事情完成时,Event Table会将这个函数移入Event Queue。
  • 主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。
  • 上述过程会不断重复,也就是常说的Event Loop(事件循环)。

js引擎存在monitoring process进程,会持续不断的检查主线程执行栈是否为空,一旦为空,就会去Event Queue那里检查是否有等待被调用的函数。

————————————分割线————————————————————

看完图文解释开始迷糊了,赶紧先看几个例子:

例1:

console.log('script start')
setTimeout(function(){
    console.log('settimeout')
})
console.log('script end')
// script start
// script end
// settimeout
例1执行.png

例2:

console.log('script start')
let promise1 = new Promise(function (resolve) {
    console.log('promise1')
    resolve()
    console.log('promise1 end')
}).then(function () {
    console.log('promise2')
})
setTimeout(function(){
    console.log('settimeout')
})
console.log('script end')
// script start
// promise1
// promise1 end
// script end
// promise2
// settimeout
例2执行.png

执行2:Promise本身是同步的立即执行函数,所以输出promise1,
步骤3:resolve()的作用是改变Promise对象的状态,并不会阻断函数的执行,所以会执行输出promise1 end。then()回调是微任务,放到微任务队列
步骤4:settimeout宏任务,放进宏任务队列
步骤6:按顺序执行完微任务队列中的所有微任务
步骤7:微任务队列执行完,开始执行下一个宏任务

例3:

async function async1(){
   console.log('async1 start');
    await async2();
    console.log('async1 end')
}
async function async2(){
    console.log('async2')
}

console.log('script start');
async1();
console.log('script end')

// script start
// async1 start
// async2
// script end
// async1 end
例3执行.png

步骤2:执行async1函数,输出async1 start,
步骤3:遇到了await语句,立即执行表达式,执行await方法
步骤4:await后面的语句放入微任务队列,相当于让出了线程,跳出了async函数体
步骤6:执行微任务队列任务,执行完看宏任务队列,为空,执行完成

例4:

async function async1() {
        console.log('async1 start');
        await async2();
        console.log('async1 end');
    }
    async function async2() {
        console.log('async2');
    }
    console.log('script start');
    setTimeout(function() {
        console.log('setTimeout');
    }, 0)
    async1();
    new Promise(function(resolve) {
        console.log('promise1');
        resolve();
    }).then(function() {
        console.log('promise2');
    });
    console.log('script end');
// script start
// async1 start
// async2
// promise1
// script end
// async1 end
// promise2
// setTimeout
例4.png

————————————分割线————————————————————
我觉得这对段放前面不好理解,先把上文搞定,再去理解下面的话:

Event Loop,即事件循环,是指浏览器或Node的一种解决JavaScript单线程运行时不会阻塞的一种机制,是js实现异步的一种方法,也是js的执行机制

JavaScript是单线程语言,但是可以开启同步任务异步任务

JavaScript中包含一个主线程(main-thread)和调用栈(call-stack),调用栈采用的是后进先出的规则,当函数执行的时候,会被添加到栈的顶部,当执行栈执行完成后,就会从栈顶移出,直到栈内被清空。

在一个线程中,事件循环是唯一的,但是任务队列(宏任务和微任务)可以拥有多个,任务队列是先进先出的数据结构

参考:https://juejin.cn/post/6844903764202094606#heading-2
https://juejin.cn/post/6844903512845860872#heading-6
https://juejin.cn/post/6844904079353708557
https://www.cnblogs.com/lideyao/p/12022717.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容