美文网首页
Event Loop

Event Loop

作者: 悄敲 | 来源:发表于2019-03-18 19:25 被阅读0次

    关于浏览器的多进程,JS单线程等涉及浏览器整体运行机制、浏览器内核、JS运行机制,请看这篇文章,全是干货,什么时候我能写出这种文章就好了。

    事件循环机制示意图.png
    基本概念:
    (1)宿主环境:可以简单理解为使用JS引擎的外部环境,常见的有浏览器和Node环境。
    (2)宏任务:宿主发起的任务(每个宏任务中包含一个微任务队列);
    (3)微任务:JS引擎发起的任务;
    上图的简单说明:
    (1)主线程运行时会产生执行栈,当JS引擎执行代码块如setTimeOut时(也可来自浏览器内核的其他线程,如鼠标点击事件监听、AJAX异步请求等),会将对应任务添加到事件触发线程中(具体应该保存在 event table 中)。
    (2)当对应的事件触发条件被触发时,事件触发线程会把事件添加到待处理事件队列(event queue)的队尾。
    (3)主线程执行栈中的代码执行完毕,就会读取事件队列中的事件,然后执行相应的回调(事件处理程序)。
    (4)循环以上步骤。
    macrotask(宏任务)与microtask(微任务)

    (事件队列中的每一个事件都是一个macrotask)
    在事件循环的某一轮中,只有一个来自 macrotask队列的宏任务会被处理。当这个宏任务处理完毕,才会处理所有可处理(available更准确)的微任务(来自 microtask queue)。而在处理微任务的过程中,可能会产生更多的微任务,这些在处理过程中新产生的微任务会进入 microtask queue。处理微任务的过程中,microtask queue 是动态的,其中的微任务会逐个依次得到处理,直至 microtask queue为空。(While these microtasks are processed, they can queue even more microtasks, which will all be run one by one, until the microtask queue is exhausted.)
    在处理微任务的过程中,可能会递归产生层次越来越深的新的微任务,耗时很久以至于宏任务中的下一个任务迟迟得不到处理,这有相应的机制去防止(例如限制递归深度)。

    task queue、microtask、macrotask 要点:
    An event loop has one or more task queues.(task queue is macrotask queue)
    Each event loop has a microtask queue.
    task queue = macrotask queue != microtask queue
    a task may be pushed into macrotask queue,or microtask queue
    when a task is pushed into a queue(micro/macro),we mean preparing work is finished,so the task can be executed now.

    分类:
    macrotasks:

    • setTimeout
    • setInterval
    • setImmediate
    • requestAnimationFrame
    • I/O
    • UI rendering

    microtasks:

    • process.nextTick
    • Promises
    • Object.observe
    • MutationObserver

    (注意,宏任务队列可能存在多个,但微任务队列只有一个。
    macrotask中的事件都是放在一个事件队列中的,而这个队列由事件触发线程维护。
    microtask中的所有微任务都是添加到微任务队列(Job Queues)中,等待当前macrotask执行完毕后执行,而这个队列应该是由JS引擎线程维护 .
    使用宏任务还是微任务的原则:Basically, use microtasks when you need to do stuff asynchronously in a synchronous way (i.e. perform this (micro-)task in the most immediate future). Otherwise, stick to macrotasks.
    microtasks的作用是用来调度应在当前执行的脚本执行结束后立即执行的任务。 例如响应事件、或者异步操作,否则就要将这些操作放到一个task(macrotask)来处理。
    JavaScript执行顺序可以简要总结如下:
    开始 -> 取task queue第一个task执行 -> 取microtask全部任务依次执行 -> 取task queue下一个任务执行 -> 再次取出microtask全部任务执行 -> …

    分割线内的内容涉及的细节较多,以chrome中运行结果为准。(不建议钻牛角尖)
    ------------------------------分割线----------------------------------------------

    <div class="outer">
        <div class="inner"></div>
    </div>
    -------------------------------------------------------------------------
     const outer=document.querySelector(".outer");
           const inner=document.querySelector(".inner");
           new MutationObserver(()=>console.log('mutate'))
                .observe(outer,{
                    attributes:true
                });
           const onClick=function () {
               console.log('click');
               setTimeout(()=>console.log('timeout'),0);
               Promise.resolve()
                   .then(()=>console.log('promise'));
               outer.setAttribute('data-random',Math.random())
           }
           inner.addEventListener('click',onClick);
           outer.addEventListener('click',onClick);
    

    猜猜看点击inner div,控制台会输出什么样的结果?
    (提示:Dispatching the 'click' event is a task. Mutation observer and promise callbacks are queued as microtasks. The setTimeout callback is queued as a task.(here task means macrotask.))。
    如果不是在页面上点击触发事件,而是执行以下JS代码,结果又是怎样?
    (提示:直接在代码中执行 .click(),会导致同步地分发(dispatch)事件,不存在事件冒泡过程。)

     inner.click();
    

    想验证的话,请查看
    ------------------------------分割线----------------------------------------------

    结论:
    1.Tasks(Macrotasks) execute in order, and the browser may render between them.
    2.Microtasks execute in order, and are executed:
    (1) after every callback, as long as no other JavaScript is mid-execution;
    (2) at the end of each task.

    相关文章

      网友评论

          本文标题:Event Loop

          本文链接:https://www.haomeiwen.com/subject/mcwbmqtx.html