Js与Nodejs的event-loop的执行机制

1,187 阅读2分钟

js是单线程

javascript在最初设计时设计成了单线程,为什么不是多线程呢?如果多个线程同时操作DOM岂不会很混乱?比如,假定JavaScript同时有两个线程,一 个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?这里所谓的单线程指的是主线程是单线程的,所以在Node 中主线程依旧是单线程的。

浏览器的event-loop

执行栈与任务队列

(1)所有同步任务都在主线程上执行,形成一个执行栈。
(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置
    一个事件。 
(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步
    任务,于是结束等待状态,进入执行栈  
    ,开始执行。 
(4)主线程不断重复上面的第三步。


  • 任务队列分为macro-task(宏任务)和micro-task(微任务)。

  • macro-task(宏任务): setTimeout, setInterval, setImmediate, I/O等

  • micro-task(微任务): process.nextTick, 原生Promise(有些实现的promise将then方法放到了宏任务中),Object.observe(已废弃), MutationObserver等


  • console.log(1);
    console.log(2);
    Promise.resolve().then(function(){
        console.log('promise')
    });
    setTimeout(function(){
        console.log('setTimeout1')
        Promise.resolve().then(function(){
            console.log('promise')
        });
    })
    setTimeout(function(){
        console.log('setTimeout2');
    });
    
    

    结果:
    1
    2
    promise
    setTimeout1
    promise
    setTimeout2
    
    浏览器 会先执行同步代码 ===> 然后查看任务队列 ===> 先执行micro-task(微任务) ===> 在执行macro-task(宏任务)
    个人理解: 有微先走微,没微就走宏。

    Nodejs的event-loop

    Nodejs与浏览器的 event-loop有些不同

    nodeJS中的宏任务和微任务在浏览器的基础上有新增了几个
    微任务
    then
    nextTick
    messageChannel
    mutationObersve

    宏任务
    setTimeout
    setInterval
    setImmediate

    nodejs的event-loop图解


    当node执行完同步代码时就会执行上图的顺序

    console.log(1);
    console.log(2);
    Promise.resolve().then(function(){
        console.log('promise')
    });
    setTimeout(function(){
        console.log('setTimeout1')
        Promise.resolve().then(function(){
            console.log('promise')
        });
    })
    setTimeout(function(){
        console.log('setTimeout2');
    });
    

    node环境里的执行顺序

    1
    2
    promise
    setTimeout1
    setTimeout2
    promise
    node 执行完同步代码 之后会先查找 微任务队列 然后逐一清空 微任务 然后走timer 清空timer(宏任务)


    node里的的 nextTick 与 setImmediate

    process.nextTick(function(){    console.log('nextTick')});setImmediate(function(){    console.log('immediate')});
    
    nextTickimmediate因为 nextTick是微任务 所以nextTick先执行