0

0

细说JavaScript事件循环机制-第二讲

韦小宝

韦小宝

发布时间:2018-03-07 15:26:32

|

2092人浏览过

|

来源于php中文网

原创

我们继续来讲javascript中的事件循环机制,第一讲的javascript事件循环机制并没有讲完,我们现在继续接着讲,对javascript事件循环机制的继续来看本篇文章吧!

在上一篇文章里面我大致介绍了JavaScript的事件循环机制,但是最后还留下了一段代码和几个问题。

那我们先从这段代码开始看哇

(function test() {
    setTimeout(function() {console.log(4)}, 0);
    new Promise(function executor(resolve) {
        console.log(1);
        for( var i=0 ; i<10000 ; i++ ) {
            i == 9999 && resolve();
        }
        console.log(2);
    }).then(function() {
        console.log(5);
    });
    console.log(3);
})()

在这段代码里面,setTimeout和Promise都被称之为任务源,来自不同任务源的回调函数会被放进不同的任务队列里面。

setTimeout的回调函数被放进setTimeout的任务队列之中。而对于Promise,它的回调函数并不是传进去的executer函数,而是其异步执行的then方法里面的参数,被放进Promise的任务队列之中。也就是说Promise的第一个参数并不会被放进Promise的任务队列之中,而会在当前队列就执行。

立即学习Java免费学习笔记(深入)”;

其中setTimeout和Promise的任务队列叫做macro-task(宏任务),当然如我们所想,还有micro-task(微任务)。

  1. macro-task包括:script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering。

  2. micro-task包括:process.nextTick, Promises, Object.observe, MutationObserver

其中上面的setImmediate和process.nextTick是Node.JS里面的API,浏览器里面并没有,这里就当举例,不必纠结具体是怎么实现的。

事件循环的顺序是从script开始第一次循环,随后全局上下文进入函数调用栈,碰到macro-task就将其交给处理它的模块处理完之后将回调函数放进macro-task的队列之中,碰到micro-task也是将其回调函数放进micro-task的队列之中。直到函数调用栈清空只剩全局执行上下文,然后开始执行所有的micro-task。当所有可执行的micro-task执行完毕之后。循环再次执行macro-task中的一个任务队列,执行完之后再执行所有的micro-task,就这样一直循环。

分析执行过程

下面分析的思路按照波同学之前所写的深入核心,详解事件循环机制中的思路进行分析。

以之前的栗子作为分析的对象,来分析事件循环机制究竟是怎么执行代码的

(function test() {
    setTimeout(function() {console.log(4)}, 0);
    new Promise(function executor(resolve) {
        console.log(1);
        for( var i=0 ; i<10000 ; i++ ) {
            i == 9999 && resolve();
        }
        console.log(2);
    }).then(function() {
        console.log(5);
    });
    console.log(3);
})()

注意下面所有图中的setTimeout任务队和最后的函数调用栈中存放的都是setTimeout的回调函数,并不是整个setTimeout定时器

PAI3JG45K0S21M[8AP}I8AV.png

1.首先,script任务源先执行,全局上下文入栈。

@F7}R(TMXRTG@YA}@19Y[.png

2.script任务源的代码在执行时遇到setTimeout,作为一个macro-task,将其回调函数放入自己的队列之中。

(Y7DEM(J8M45`MW7I`]ON3P.png

3.script任务源的代码在执行时遇到Promise实例。Promise构造函数中的第一个参数是在当前任务直接执行不会被放入队列之中,因此此时输出 1 。

0`@U79F427SBFX(][G`QC12.png

(1UH@Q5OX430O7G(O~ZA}JP.png

Codiga
Codiga

可自定义的静态代码分析检测工具

下载

4.在for循环里面遇到resolve函数,函数入栈执行之后出栈,此时Promise的状态变成Fulfilled。代码接着执行遇到console.log(2),输出2。

5IIZM~S$L@XZBD$%U$9G408.png

5.接着执行,代码遇到then方法,其回调函数作为micro-task入栈,进入Promise的任务队列之中。

(U`W$DPY7P8)LC_70CQ)K1G.png

6.代码接着执行,此时遇到console.log(3),输出3。

T@ZO_@8L@%YL6A2Q12~O)9A.pngYB6H8HXS8{8)(N]N80VB3MH.png

7.输出3之后第一个宏任务script的代码执行完毕,这时候开始开始执行所有在队列之中的micro-task。then的回调函数入栈执行完毕之后出栈,这时候输出5

WDQDKWM9Q}S56O(1WB7HF$O.png

8.这时候所有的micro-task执行完毕,第一轮循环结束。第二轮循环从setTimeout的任务队列开始,setTimeout的回调函数入栈执行完毕之后出栈,此时输出4。

总结

总的来说就是:

1、不同的任务会放进不同的任务队列之中。

2、先执行macro-task,等到函数调用栈清空之后再执行所有在队列之中的micro-task。

3、等到所有micro-task执行完之后再从macro-task中的一个任务队列开始执行,就这样一直循环。

4、当有多个macro-task(micro-task)队列时,事件循环的顺序是按上文macro-task(micro-task)的分类中书写的顺序执行的。

测试

说到这里,我们应该都明白了,下面是一个复杂的代码段(改自深入核心,详解事件循环机制),里面有混杂着的micro-task和macro-task,自己画图试试流程哇,然后再用node执行看看输出的顺序是否一致。

console.log('golb1');
setImmediate(function() {
    console.log('immediate1');
    process.nextTick(function() {
        console.log('immediate1_nextTick');
    })
    new Promise(function(resolve) {
        console.log('immediate1_promise');
        resolve();
    }).then(function() {
        console.log('immediate1_then')
    })
})
setTimeout(function() {
    console.log('timeout1');
    process.nextTick(function() {
        console.log('timeout1_nextTick');
    })
    new Promise(function(resolve) {
        console.log('timeout1_promise');
        resolve();
    }).then(function() {
        console.log('timeout1_then')
    })
    setTimeout(function() {
    	console.log('timeout1_timeout1');
    process.nextTick(function() {
        console.log('timeout1_timeout1_nextTick');
    })
    setImmediate(function() {
    	console.log('timeout1_setImmediate1');
    })
    });
})
new Promise(function(resolve) {
    console.log('glob1_promise');
    resolve();
}).then(function() {
    console.log('glob1_then')
})
process.nextTick(function() {
    console.log('glob1_nextTick');
})

讲到这里我们的细说JavaScript事件循环机制也就正式讲完了,看不懂了两篇结合起来看看,练练即可!

先看看我吧:

细说JavaScript事件循环机制-第一讲

相关文章

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

37

2026.01.14

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

19

2026.01.13

PHP 高性能
PHP 高性能

本专题整合了PHP高性能相关教程大全,阅读专题下面的文章了解更多详细内容。

37

2026.01.13

MySQL数据库报错常见问题及解决方法大全
MySQL数据库报错常见问题及解决方法大全

本专题整合了MySQL数据库报错常见问题及解决方法,阅读专题下面的文章了解更多详细内容。

19

2026.01.13

PHP 文件上传
PHP 文件上传

本专题整合了PHP实现文件上传相关教程,阅读专题下面的文章了解更多详细内容。

16

2026.01.13

PHP缓存策略教程大全
PHP缓存策略教程大全

本专题整合了PHP缓存相关教程,阅读专题下面的文章了解更多详细内容。

6

2026.01.13

jQuery 正则表达式相关教程
jQuery 正则表达式相关教程

本专题整合了jQuery正则表达式相关教程大全,阅读专题下面的文章了解更多详细内容。

3

2026.01.13

交互式图表和动态图表教程汇总
交互式图表和动态图表教程汇总

本专题整合了交互式图表和动态图表的相关内容,阅读专题下面的文章了解更多详细内容。

45

2026.01.13

nginx配置文件详细教程
nginx配置文件详细教程

本专题整合了nginx配置文件相关教程详细汇总,阅读专题下面的文章了解更多详细内容。

9

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 3.6万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 2.2万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 2.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号