首页 web前端 js教程 细说JavaScript事件循环机制-第一讲

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

Mar 07, 2018 pm 02:56 PM
javascript js 机制

Javascript中的事件循环机制,很多文章都只说了Javascript的事件分为同步任务和异步任务遇到同步任务就放在执行栈中执行,而碰到异步任务就放到任务队列之中,等到执行栈执行完毕之后再去执行任务队列之中的事件。本篇文章讲的很不错!我们一起来看看吧!我们直接进入正题吧!

函数调用栈与任务队列

Javascript有一个main thread 主进程和call-stack(一个调用堆栈),在对一个调用堆栈中的task处理的时候,其他的都要等着。当在执行过程中遇到一些类似于setTimeout等异步操作的时候,会交给浏览器的其他模块(以webkit为例,是webcore模块)进行处理,当到达setTimeout指定的延时执行的时间之后,task(回调函数)会放入到任务队列之中。一般不同的异步任务的回调函数会放入不同的任务队列之中。等到调用栈中所有task执行完毕之后,接着去执行任务队列之中的task(回调函数)。

用Philip Roberts的演讲《Help, I’m stuck in an event-loop》之中的一张图表示就是

6S1K1K}%B_~1MH{219$IF{F.png

在上图中,调用栈中遇到DOM操作、ajax请求以及setTimeout等WebAPIs的时候就会交给浏览器内核的其他模块进行处理,webkit内核在Javasctipt执行引擎之外,有一个重要的模块是webcore模块。对于图中WebAPIs提到的三种API,webcore分别提供了DOM Binding、network、timer模块来处理底层实现。等到这些模块处理完这些操作的时候将回调函数放入任务队列中,之后等栈中的task执行完之后再去执行任务队列之中的回调函数。

从setTimeout看事件循环机制

下面用Philip Roberts的演讲中的一个栗子来说明事件循环机制究竟是怎么执行setTimeout的。

J62(IHDKQI}YZJQ0H$`3(YU.png

首先main()函数的执行上下文入栈

R%DCA_3[8SX3~0E(HA6R%YT.png

代码接着执行,遇到console.log(‘Hi’),此时log(‘Hi’)入栈,console.log方法只是一个webkit内核支持的普通的方法,所以log(‘Hi’)方法立即被执行。此时输出’Hi’。

4D{W3IU7[X$37LR2FT9MHBX.png

当遇到setTimeout的时候,执行引擎将其添加到栈中。

[$~DQ5J3KUN${FT2Q4BFUT9.png

调用栈发现setTimeout是之前提到的WebAPIs中的API,因此将其出栈之后将延时执行的函数交给浏览器的timer模块进行处理。

%_I[([5(T~2Y@%}I}@2[6KK.png

timer模块去处理延时执行的函数,此时执行引擎接着执行将log(‘SJS’)添加到栈中,此时输出’SJS’。

X18[LY)~QBZ1QM%U[4T9UOJ.png

当timer模块中延时方法规定的时间到了之后就将其放入到任务队列之中,此时调用栈中的task已经全部执行完毕。

8`W3PJ1{$STG$)71D]J]SJS.png

E3A2KE41YC_Q0[1HM${6B`B.png

调用栈中的task执行完毕之后,执行引擎会接着看执行任务队列中是否有需要执行的回调函数。这里的cb函数被执行引擎添加到调用栈中,接着执行里面的代码,输出’there’。等到执行结束之后再出栈。

小结

上面的这一个流程解释了当浏览器遇到setTimeout之后究竟是怎么执行的,相类似的还有前面图中提到的另外的API以及另外一些异步的操作。
总结上文说的,主要就是以下几点:

1、所有的代码都要通过函数调用栈中调用执行。

2、当遇到前文中提到的APIs的时候,会交给浏览器内核的其他模块进行处理。

3、任务队列中存放的是回调函数。

4、等到调用栈中的task执行完之后再回去执行任务队列之中的task。

测试

for (var i = 0; i < 5; i++) {
    setTimeout(function() {
      console.log(new Date, i);
    }, 1000);
}
console.log(new Date, i);
登录后复制

这段代码是我从网上前不久的一篇文章80%应聘者都不及格的 JS 面试题中找到的,现在我们就分析一下这段代码究竟是怎么输出最后文章中所说的最后的执行状态

40% 的人会描述为:5 -> 5,5,5,5,5,即第 1 个 5 直接输出,1 秒之后,输出 5 个 5;

1、首先i=0时,满足条件,执行栈执行循环体里面的代码,发现是setTimeout,将其出栈之后把延时执行的函数交给Timer模块进行处理。

2、当i=1,2,3,4时,均满足条件,情况和i=0时相同,因此timer模块里面有5个相同的延时执行的函数。

3、当i=5的时候,不满足条件,因此for循环结束,console.log(new Date, i)入栈,此时的i已经变成了5。因此输出5。

4、此时1s已经过去,timer模块将5个回调函数按照注册的顺序返回给任务队列。

5、执行引擎去执行任务队列中的函数,5个function依次入栈执行之后再出栈,此时的i已经变成了5。因此几乎同时输出5个5。

6、因此等待的1s的时间其实只有输出第一个5之后需要等待1s,这1s的时间是timer模块需要等到的规定的1s时间之后才将回调函数交给任务队列。等执行栈执行完毕之后再去执行任务对列中的5个回调函数。这期间是不需要等待1s的。因此输出的状态就是:5 -> 5,5,5,5,5,即第1个 5 直接输出,1s之后,输出 5个5;

问题

看到这里,对事件循环机制有了一个大概的了解了,可是细想,其中还有一些另外值得深入的问题。
下面通过一个栗子来说明:

(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);
})()
登录后复制

在这段代码里面,多了一个promise,那么我们可以思考下面这个问题:

1、promise的task会放在不同的任务队列里面,那么setTimeout的任务队列和promise的任务队列的执行顺序又是怎么的呢?

2、到这里大家看了我说了这么多的task,那么上文中一直提到的task究竟包括了什么?具体是怎么分的?

如果到这里大家还是没太懂的话,那么接下来我会接着深入再细说不同task的事件循环机制。

相关推荐:

js事件循环机制示例分析

以上是细说JavaScript事件循环机制-第一讲的详细内容。更多信息请关注PHP中文网其他相关文章!

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

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

推荐:优秀JS开源人脸检测识别项目 推荐:优秀JS开源人脸检测识别项目 Apr 03, 2024 am 11:55 AM

人脸检测识别技术已经是一个比较成熟且应用广泛的技术。而目前最为广泛的互联网应用语言非JS莫属,在Web前端实现人脸检测识别相比后端的人脸识别有优势也有弱势。优势包括减少网络交互、实时识别,大大缩短了用户等待时间,提高了用户体验;弱势是:受到模型大小限制,其中准确率也有限。如何在web端使用js实现人脸检测呢?为了实现Web端人脸识别,需要熟悉相关的编程语言和技术,如JavaScript、HTML、CSS、WebRTC等。同时还需要掌握相关的计算机视觉和人工智能技术。值得注意的是,由于Web端的计

简易JavaScript教程:获取HTTP状态码的方法 简易JavaScript教程:获取HTTP状态码的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教程:如何获取HTTP状态码,需要具体代码示例前言:在Web开发中,经常会涉及到与服务器进行数据交互的场景。在与服务器进行通信时,我们经常需要获取返回的HTTP状态码来判断操作是否成功,根据不同的状态码来进行相应的处理。本篇文章将教你如何使用JavaScript获取HTTP状态码,并提供一些实用的代码示例。使用XMLHttpRequest

PHP与JS开发技巧:掌握绘制股票蜡烛图的方法 PHP与JS开发技巧:掌握绘制股票蜡烛图的方法 Dec 18, 2023 pm 03:39 PM

随着互联网金融的迅速发展,股票投资已经成为了越来越多人的选择。而在股票交易中,蜡烛图是一种常用的技术分析方法,它能够显示股票价格的变化趋势,帮助投资者做出更加精准的决策。本文将通过介绍PHP和JS的开发技巧,带领读者了解如何绘制股票蜡烛图,并提供具体的代码示例。一、了解股票蜡烛图在介绍如何绘制股票蜡烛图之前,我们首先需要了解一下什么是蜡烛图。蜡烛图是由日本人

js和vue的关系 js和vue的关系 Mar 11, 2024 pm 05:21 PM

js和vue的关系:1、JS作为Web开发基石;2、Vue.js作为前端框架的崛起;3、JS与Vue的互补关系;4、JS与Vue的实践应用。

如何在JavaScript中获取HTTP状态码的简单方法 如何在JavaScript中获取HTTP状态码的简单方法 Jan 05, 2024 pm 01:37 PM

JavaScript中的HTTP状态码获取方法简介:在进行前端开发中,我们常常需要处理与后端接口的交互,而HTTP状态码就是其中非常重要的一部分。了解和获取HTTP状态码有助于我们更好地处理接口返回的数据。本文将介绍使用JavaScript获取HTTP状态码的方法,并提供具体代码示例。一、什么是HTTP状态码HTTP状态码是指当浏览器向服务器发起请求时,服务

js刷新当前页面的方法 js刷新当前页面的方法 Jan 24, 2024 pm 03:58 PM

js刷新当前页面的方法:1、location.reload();2、location.href;3、location.assign();4、window.location。详细介绍:1、location.reload(),使用location.reload()方法可以重新加载当前页面;2、location.href,可以通过设置location.href属性来刷新当前页面等等。

深入了解CSS布局重新计算和渲染的机制 深入了解CSS布局重新计算和渲染的机制 Jan 26, 2024 am 09:11 AM

CSS回流(reflow)和重绘(repaint)是网页性能优化中非常重要的概念。在开发网页时,了解这两个概念的工作原理,可以帮助我们提高网页的响应速度和用户体验。本文将深入探讨CSS回流和重绘的机制,并提供具体的代码示例。一、CSS回流(reflow)是什么?当DOM结构中的元素发生可视性、尺寸或位置改变时,浏览器需要重新计算并应用CSS样式,然后重新布局

JS中__proto__与prototype的区别 JS中__proto__与prototype的区别 Feb 19, 2024 pm 01:38 PM

JS中__proto__和prototype是两个与原型相关的属性,它们在功能上稍有不同。本文将具体介绍并比较这两者的区别,并提供相应的代码示例。首先,我们先来了解一下它们的含义和用途。proto__proto__是对象的一个内置属性,它用于指向该对象的原型。每个对象都有一个__proto__属性,包括自定义对象、内置对象和函数对象。通过__proto__属

See all articles