EventLoop二三事

148 阅读2分钟

浏览器中的EventLoop

嘿,你觉得下面的代码运行结果是什么呢?

console.log('start')

setTimeout( function () {
  console.log('setTimeout')
}, 0 )

Promise.resolve().then(function() {
  console.log('promise1');
}).then(function() {
  console.log('promise2');
});

console.log('end')

可以先尝试进行如下分析

1.先将同步执行的代码找出,首先打印的一定是start end

2.setTimeout、Promise是否有优先级 还是根据顺序来执行?

运行一下代码,答案是:start、end、promise1、promise2、setTimeout

需要理解的知识点

1.执行栈

javascript是单线程,也就是只有一个主线程,主线程有一个栈,每一个函数执行时都会生成新的execution context(执行上下文),执行上下文会包含一些当前函数的参数、局部变量之类的信息,它会被推入栈中,running execution context(正在执行的上下文)始终处于栈的顶部。当函数执行完后,它的执行上下文会从栈弹出

粟子:

function bar(){
    console.log('bar')
}
function foo(){
    console.log('foo');
    bar();
}
foo();

执行过程中栈的变化:

2.宏任务 setTimeout、setImmediate

微任务 promises、processs.nextTick、MutationObserver

3.整个最基本的Event Loop如图所示

  • queue可以看做一种数据结构,用以存储需要执行的函数
  • setTimeout注册的函数,等到期后进入task队列
  • 其余API注册函数直接进入自身对应的macrotask/microtask队列
  • Event Loop继续检查microtask队列是否为空,依次执行直至清空microtask队列
  • 执行macrotask队列

Node中的EventLoop

Node.js也是单线程的Event Loop,但是它的运行机制不同于浏览器环境

根据上图,Node.js的运行机制如下

1.V8引擎解析javascript脚本 2.解析后的代码 调用node API 3.libuv库负责Node API的执行。它将不同的任务分配给不同的线程,形成一个Event Loop(事件循环),以异步的方式将任务的执行结果返回给V8引擎 4.V8引擎再将结果返回给用户

整个最基本的Event Loop 如图所示

练习

setTimeout(()=>{
    console.log('timeout1')
    Promise.resolve().then(data=>{
        console.log('promise2')
    })
})
Promise.resolve().then(()=>{
    console.log('promise1')
    setTimeout(()=>{
        console.log('timeout2')
    })
})
let fs = require('fs')
fs.readFile('a.txt','utf-8',()=>{
    setTimeout(()=>{
        console.log('timeout2')
    },0)
    setImmediate(()=>{
        console.log('setImmediate')
    })
})

运行一下吧 看下结果是否你想的呢???