zl程序教程

您现在的位置是:首页 >  后端

当前栏目

浅谈js事件循环机制

JS事件循环 机制 浅谈
2023-09-27 14:26:17 时间

太多关于js事件循环机制的面试问题了,必须要好好看一眼小小的总结一波;于是查了很多资料,看了很多相关文档;

得出以下姿势;先来张图解释下

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    <body>
        <div id="root">
            <h1>JS事件的循环</h1>
            <h3>参考阮一峰大神:http://www.ruanyifeng.com/blog/2014/10/event-loop.html</h3>
            <p>同步任务:指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;</p>
            <p>异步任务:指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。</p>
            <p>异步执行的运行机制如下:(同步执行也是如此,因为它可以被视为没有异步任务的异步执行。)</p>
            <p>(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。</p>
            <p>(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。</p>
            <p>(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。</p>
            <p>(4)主线程不断重复上面的第三步。只要主线程空了,就会去读取"任务队列"【事件的队列 or 消息的队列】,这就是JavaScript的运行机制。这个过程会不断重复</p>
            <p>process.nextTick和setImmediate的一个重要区别:多个process.nextTick语句总是在当前"执行栈"一次执行完,多个setImmediate可能则需要多次loop才能执行完</p>
            <p>
                宏任务(macrotask):script(整体代码)、setTimeout、setInterval、UI 渲染、 I/O、postMessage、 MessageChannel、setImmediate(Node.js 环境)
                微任务(microtask):Promise、 MutaionObserver、process.nextTick(Node.js环境)
            </p>
            <p>
                同步代码:代码单线执行,发送服务器请求后,等待返回数据,会出现网页空白(阻塞网页运行) 如alert for循环
                异步代码:代码发送请求后继续执行后续代码,不等待服务器返回数据(网页运行流畅)
                js中常见的异步执行代码:
                1.ajax请求:异步 JavaScript 和 XML
                2.定时器、setTimeout:间隔一段时间才会执行,
                3.事件处理函数:满足事件触发条件才会执行
            </p>
        </div>
        <script type="text/javascript">
            // 遇到【同步任务】直接执行,遇到【异步任务】分类为宏任务(macro-task)和微任务(micro-task)。
            // 宏任务:整体的Script setTimeout setInterval
            // 微任务:Promise process.nextTick
            // 所谓"回调函数"(callback),就是那些会被主线程挂起来的代码。异步任务必须指定回调函数,当主线程开始执行异步任务,就是执行对应的回调函数
            // 任务队列是一个先进先出的数据结构
            // 主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)
            console.log('script start');
            
            setTimeout(function () {
              console.log('setTimeout');
            }, 0);
            
            Promise.resolve()
              .then(function () {
                console.log('promise1');
              })
              .then(function () {
                console.log('promise2');
              });
            
            console.log('script end');
            // 依次输出结果
            // script start -> script end -> promise1 -> promise2 -> setTimeout
            
            // for (let i = 0; i < 99999; i++) {
            //     console.log("我在执行 但用户不知道")
            // }
            // console.log("循环完毕才可以打印")
            
            /*****************同步代码异步代码有趣的打印****************/
            for (var i = 0; i < 10; i++) {
                setTimeout(function() {
                    console.log(i,'输出十次10')
                }, 0)
            }
                
            // 立刻执行函数
            for (var i = 0; i < 10; i++) {
                (function(i){   
                    setTimeout(function (){
                      console.log(i, '输出0-9'); 
                     },1000); 
                })(i); 
            }

            for (let i = 0; i < 10; i++) {
                setTimeout(function() {
                    console.log(i,'输出0-9')
                }, 0)
            }
            
            /*
            结论:
             有微则微,无微则宏 【如果微任务列表里面有任务,会执行完毕后在执行宏任务】
             关于promise或者es语法参考:https://es6.ruanyifeng.com/#docs/promise
            */
        </script>
    </body>
</html>

鄙人才疏学浅,如有不对请指出!!!转载注明出处!!!谢谢合作!!!