• node.js中对Event Loop事件循环的理解


    javascript是单线程的,所以任务的执行都需要排队,任务分为两种,一种是同步任务,一种是异步任务。

    同步任务是进入主线程上排队执行的任务,上一个任务执行完了,下一个任务才会执行。

    异步任务是不进入主线程,而是进入一个 "任务队列" 里,"任务队列" 通知主线程,该异步任务才会进入主线程执行。

    任务的运行机制如下:

    1、所有同步任务在主线程上执行,形成一个 "执行栈",注意栈是先进后出的。

    2、主线程外,有一个 "任务队列" ,只要异步任务处理完有结果了,就在 "任务队列" 中放置一个事件,注意队列是先进先出的。

    3、一旦 "执行栈" 中所有同步任务执行完毕。系统读取 "任务队列" 中的事件,对应的异步任务。放入 "执行栈" 中,开始执行。

    4、主线程不断重复第三步,这种循环从 "任务队列" 中读取事件处理的这种运行机制称为Event Loop(事件循环)。

    "执行栈" 中的同步代码总是比 "任务队列"中的异步任务之前运行。

    function fun() {
        setTimeout(function () {
            console.log('异步任务');
        }, 0);
        console.log(1);
        console.log(2);
        console.log(3);
        console.log(4);
        console.log(5);
    }
    fun();

    上面的代码,console.log代码写在setTimeout后面,但仍然先执行。

    "任务队列" 是一个队列,队列的特性是先进先出。看下面代码:

    function fun() {
        console.log(1);
        setTimeout(function () {
            console.log(2);
            setTimeout(function () {
                console.log(3);
            }, 0);
        }, 0);
        console.log(4);
    }
    fun();

    输出结果为 1  4  2  3,打印 2 的setTimeout任务比打印 3 的setTimeout任务先进入队列,所以会先运行。

    对于异步操作,像ajax,只有操作成功后返回结果,才会进入 "任务队列" 中,而不是调用的时候就放入队列中。看下面代码:

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <script>
        function ajax() {
            var xhr = new XMLHttpRequest();
            xhr.open('GET', 'https://mail.163.com/', true);
            xhr.send();
            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    console.log(xhr.responseText);
                }
            };
        }
        function fun() {
            console.log(1);
            ajax();
            setTimeout(function () {
                console.log(2);
            }, 1000);
            console.log(3);
        }
        fun();
    </script>
    </body>
    </html>

    ajax() 与 setTimeout 谁先进入队列,谁先输出,是需要看两者消耗时间,谁更短。时间短的会先进入队列先运行。

    setTimeout 与 setInterval 运行机制一样,都是在指定时间把事件插入到 "任务队列" 尾部。区别是前者只执行一次,后者可反复执行。

    node.js 还为我们提供了,process.nextTick 和 setImmediate 与 "任务队列" 有关的方法。

    process.nextTick 会把回调函数放在当前 "执行栈" 的尾部。也就是说是在读取 "任务队列" 之前运行。

    function fun() {
        console.log(1);
    
        setTimeout(function () {
            console.log(2);
        }, 0);
    
        process.nextTick(function () {
            console.log(3);
            process.nextTick(function () {
                console.log(4);
            });
        });
        process.nextTick(function () {
            console.log(5);
        });
    
        console.log(6);
    }
    fun();

    上面的代码会输出 1  6  3  5  4  2 ,注意process.nextTick会把回调函数放在 "执行栈" 的尾部。

    同步代码最先输出 1  6,然后 3 的先放入尾部,然后 5 的跟在 3 后面。3先执行,然后把 4 放入到 5 的后面。5执行完后,再执行4,最后读取 "任务队列" 中的输出2。

    setImmediate 会把回调函数放在当前 "任务队列" 的尾部。也就是下一次事件循环Event Loop时执行。

    function fun() {
        console.log(1);
    
        setTimeout(function () {
            console.log(2);
        }, 0);
    
        setImmediate(function () {
            console.log(3);
        });
    
        console.log(4);
    }
    fun();

    上面的代码是会输出 1  4  2  3 还是 1  4  3  2 是不确定的,因为setTimeout 与 setImmediate 都会在下一次事件循环Event Loop中触发,所以输出是不确定的。

  • 相关阅读:
    C基础之移位操作
    实现itoa()
    Python的time模块的clock方法在不同平台的效果不同
    __stdcall与__cdecl之区别浅析及相关知识
    Python 字典 dictionary changed size during iteration
    Windows下printf输出long long类型
    inotify也会爆棚
    一条对“失控的腾讯帝国:企鹅无法把控手机市场”的评论
    imfunny程序员的增量发展
    程序员第一定律:关于技能和收入
  • 原文地址:https://www.cnblogs.com/jkko123/p/10222859.html
Copyright © 2020-2023  润新知