js sleep函数_简单而面试中又常见的知识点:JS执行机制

610dcb0b7272e1304754e3551c3e1cd9.png

在开始讲解之前,我们先来看一段代码:

console

各位小伙伴觉得上面的结果输出会是多少呢?如果你没有了解过javascript的执行机制的话,上面的题目可能会让你崩溃。

不过别着急,先往下看,我保证你看到最后,能轻轻松松写出上面代码的答案,并且完全了解其中的原理。

d82f6bfadbd969a9eacbf152417c7b8d.gif

​ 首先,希望大家记住一个要点,javascript是单线程的语言

因此,所有的javascript的异步特性都是基于单线程实现的,记住了这个特点,我们再去理解javascript的很多机制就容易很多了。

我们先从简单的代码说起,来引出今天的概念。

console

我想小伙伴们对上面结果都不会有疑问,setTimeout是我们常用来做延迟执行的全局函数。它接受两个参数,要执行的函数a和等待的秒数x,函数a会在程序经过x秒后执行。

这里引出我们的第一个概念:同步函数和异步函数。上面的函数a就是异步函数了,它不是立刻执行的函数,而是要等待一段时间,或者说满足一定的条件之后才执行的函数。

不过,有时候我们明明设置了3秒的定时,但是却发现函数并没有在3秒后执行,有时候会更久,这又是为什么呢?

这要从javascript的执行原理说起,js执行的时候,有一个专门存放异步函数的地方,称之为Event Table,而当异步函数已经满足回调的执行条件之后(比如时间过了x秒,异步请求返回了结果等等),原本放在Event Table的异步函数就会被放进一个队列中,这个队列称为Event Queue。

不要觉得这个队列很深奥,其实就是一个排队,里面放的都是回调函数,它们正一个个等待着按顺序执行自身呢。来看下面的代码:

从上面结果我们可以看出,setTimeout并非是在setTimeout调用之后经过3秒就马上输出结果"setTimeout执行啦~",而是等待下方的sleep函数执行完毕后才输出的结果。

前面我已经说过,要牢记javascript是单线程,那么它就一次只能运行一个一段代码。

因此,即使处于异步队列的setTimeout函数已经满足执行条件了,但是它还是得等待在Event Queue中,直到主线程执行完毕才能执行。

所以请记住,js会先执行主线程的同步代码,遇到setTimeout就将其回调函数注册在Event Table中,然后当异步函数满足执行条件之后,就会被放入Event Queue中,但是并不能马上执行,而是得等待主线程剩余代码执行完毕,队列中的函数才能按顺序执行。


我想小伙伴们看到这里,已经明白一点js的执行机制了,那么我们一鼓作气,继续深入一下(其实也很简单),Promise和process又是怎样的执行机制呢?

在放代码之前,我先介绍两个基本概念:

  • process.nextTick,我们知道浏览器环境下的setTimeout,那么process.nextTick就相当于在node环境下执行的setTimeout。
  • 宏任务和微任务,主线程一直在执行script代码,还有setTimeout、setInterval函数就是宏任务,而Promise.then,process.nextTick则是微任务。

接下来,我们看一段代码:

console

emmm,这里的结果是不是就有点微妙了。

记得我们刚才说的宏任务和微任务吗,js的执行机制中,先是执行完宏任务中的同步代码,接着执行微任务,接着执行宏任务的异步代码。这样说可能有点绕,我们结合上面的代码来看。

  • 代码一开始执行,执行的就是全局代码,也就是宏任务的同步代码;
  • 遇到console.log,直接执行,输出"程序执行开始~";
  • 接着执行,遇到setTimeout函数,将其回调函数注册进宏任务的Event Queue(注意:宏任务和微任务分别有自己的Event Queue);
  • 接着遇到new Promise,立刻执行(new Promise里面的函数是立刻执行的,只有.then函数里面才是放到微任务去执行的,不要搞混咯~),输出"promise开始执行~";
  • 接着遇到promise.then函数,将其回调函数注册到微任务的Event Queue;
  • 接着继续执行,遇到console.log,直接输出"程序执行结束~"
  • 到这里,宏任务的同步代码就全部执行完毕了,这时候,js引擎会去检查微任务的Event Queue中是否存在回调函数,这时微任务的Queue中还有一个函数未执行,因此在这时候执行,输出"promise执行结束~";
  • 当微任务的所有回调函数被执行完了之后,一次事件循环就结束了。
  • 这时候js引擎会检查宏任务的Event Queue中是否还有未执行的函数,如果还有,将会开启下一轮的事件循环。由于此时我们宏任务的Event Queue中还有未执行的setTimeout,所以开启下一轮事件循环,执行setTimeout回调,输出"setTimeout执行啦~"

能坚持到这里的小伙伴,相信你已经学到了不少,给自己点个赞吧

6f88fcd93667990082c2803a3b6f8f4e.png

接下来,我们再来看一下加上process.nextTick之后的一个例子:

console

是不是有一点一开始那块代码的味道了,上面的输出结果也很容易理解:先是执行了同步代码,输出:1 3 6 9,然后输出微任务中的process.nextTick的回调:5 8,然后输出Promise.then中的回调:4 7,最后输出setTimeout的2,是不是一目了然。

上面唯一要注意点的就是:process.nextTick是要比Promise.then先执行的(也许不同node版本环境下不同,这个要看具体执行结果)。


好啦!终于这篇文章也要接近尾声了,还在看的小伙伴再给自己点个赞吧,当然也可以给我点个赞~你每一个小小的支持都是我坚持下去的最大动力。

接下来要进入最后的重头戏,按照我们前面所讲的知识,分析刚开始的代码的执行结果。这里再贴下一开始的代码,最终结果我会在文章最后再贴出来,所以小伙伴们也可以自己先看下,最后比对结果是否和文中的一致。

console

接下来是分析过程:

  • 程序开始,执行宏任务同步代码,遇到console.log,输出:1;
  • 遇到setTimeout1,将其放入宏任务Event Queue中;
  • 遇到process.nextTick1,放入微任务Event Queue中;
  • 遇到new Promise,直接执行其中的代码,输出:7;
  • 遇到Promise.then1函数,将其放入微任务Event Queue;
  • 继续执行,遇到setTimeout2,放入宏任务Event Queue;
  • 此时任务队列状态:
    • 宏Queue: setTimeout1,setTimeout2;
    • 微Queue: process.nextTick1、Promise.then1;
  • 至此,宏任务同步代码执行完毕,检测微任务队列是否存在任务,由于存在两个微任务,所以这时候执行微任务;
  • 先执行process.nextTick1,输出:6;
  • 接着执行Promise.then1,输出: 8;
  • 微任务执行完毕后,一次事件循环结束,js引擎持续检测宏任务中是否存在任务,存在的话开启下一次事件循环;由于存在两个setTimeout,所以在满足setTimeout执行条件后,开启下一次事件循环,执行回调函数;
  • 先执行setTimeout1,遇到console.log,输出:2;
  • 接着遇到process.nextTick2,放入微任务Event Queue;
  • 继续执行遇到new Promise,直接执行,输出:4;
  • 然后遇到Promise.then2,放入微任务Event Queue;
  • 至此setTimeout1执行完毕,此时任务队列状态:
    • 宏Queue: setTimeout2;
    • 微Queue: process.nextTick2、Promise.then2;
  • js引擎检查微任务Event Queue中还存在两个微任务,因此执行这两个微任务;
  • 先执行process.nextTick2,输出:3;
  • 接着执行Promise.then2,输出:5;
  • 微任务执行完毕,第二次事件循环结束;
  • js引擎持续检查宏任务Event Queue中是否还有未执行函数,检测到还有setTimeout2未执行,因此开启第三轮的事件循环;
  • 执行setTimeout2,遇到console.log,输出:9;
  • 又遇到process.nextTick3,放入微任务队列;
  • 遇到new Promise,直接执行,输出:11;
  • 遇到Promise.then3,放入微任务队列;
  • 至此,setTimeout2执行完毕,此时任务队列状态:
    • 宏Queue: 无;
    • 微Queue: process.nextTick3、Promise.then3;
  • js引擎在检测是否存在未执行的微任务,由于还有两个微任务未执行,因此将其执行;
  • 先执行process.nextTick3,输出:10;
  • 接着执行Promise.then3,输出:12;
  • 至此,微任务执行完毕,事件循环结束;

最后程序输出结果:1 7 6 8 2 4 3 5 9 11 10 12


看到这里的小伙伴们,给自己点第三个赞吧。

怎么样,是不是觉得已经完全掌握了js的执行机制,其实宏任务和微任务除了上文提到的那些,还有一些其他的,可以下来自己再去了解下~

最后,感谢大家的阅读,如果觉得文章写的还可以的话,可以给我点个赞、点个关注、或者直接关注本人,我会持续分享更多优质的技术文章,我们一起加油吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/498928.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

护卫神怎么增加php版本_护卫神php套件 php版本升级方法(php5.5.24)

最近小编开始学习研究win2008 r2的php环境配置,发现护卫神的php套件非常好用,安装简单,但是因为php版本不是最新的版本,所以就想将php升级下,因为新版的php修复了一些bug所以这里就分享下方法,需要的朋友可…

servlet中doget和dopost的区别_Servlet学习

一.HTTP协议浏览器 ----------------------------------------->服务器请求 http协议&#xff08;包含&#xff1a;1.请求行2.请求头3.空行4.请求实体&#xff09;url浏览器<-------------------------------------------服务器 响应htmlcssjsdata数据特点&#xff1a; 1…

python numpy dtype object_如何将(dtype = object)numpy数组值设置为Python列表,而不将numpy解释为值列表?...

我有一个dtype object数组,其中的值是Python列表或np.nan.我想用[无](不是无)替换np.nan的值.对于一个纯Python列表,我已经可以使用[x if(x不是np.nan)其他[无] for x in s],并且将数组转换为列表对我来说很好,但是出于好奇,我想知道如何使用numpy数组来完成这项工作.困难在于…

php curl跨域cookie_php使用curl带cookie访问一直失败求助

Launcher:感谢你在百忙中抽空帮我。刚才我做了个对比&#xff1a;1、使用Microsoft Network Monitor 监听apache发送的数据包2、使用Microsoft Network Monitor 截获ie登录目标后台3、使用Microsoft Network Monitor 截获firefox登录目标后台由第一点得到&#xff1a;cookie确实…

python如何用idle启动_Python从IDLE启动的方法

学习Python就要先学会安装和启动&#xff0c;目前Python的启动方法有两种&#xff0c;从IDLE启动是比较常见的&#xff0c;也是小码王老师今天要教大家的&#xff0c;广大家长、小朋友们一起来学习了解一下吧。在Start(开始)菜单中&#xff0c;可以看到“Python2.5”下面的“ID…

java xml 节点路径,SelectSingleNode使用XPath为已知良好的xml节点路径返回null

回答(9)2 years ago我强烈怀疑问题与名称空间有关 . 尝试摆脱名称空间&#xff0c;你会没事的 - 但显然这对你的实际情况没有帮助&#xff0c;我认为这个文件是固定的 .我不记得如何在XPath表达式中指定命名空间&#xff0c;但我确信这是问题所在 .编辑&#xff1a;好的&#x…

php fastcgi exp,nginx +phpfastcgi 环境下 导出excel文件,超时,数据被截断问题,解决...

nginx 错误日志显示&#xff0c;访问超时2015/09/16 07:18:43 [error] 2108#0: *6 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 192.168.138.7, server: localhost, request: "GET /test/index.php?mlists.e…

python爬虫软件安装不了_Mac os 下 python爬虫相关的库和软件的安装

由于最近正在放暑假&#xff0c;所以就自己开始学习python中有关爬虫的技术&#xff0c;因为发现其中需要安装许多库与软件所以就在这里记录一下以避免大家在安装时遇到一些不必要的坑。一. 相关软件的安装&#xff1a;1. homebrew:homebrew 是mac os系统下的包管理器由于功能齐…

php中文删除乱码部分,PHP中文乱码解决办法

一&#xff0e; 首先是PHP网页的编码1. php文件本身的编码与网页的编码应匹配a. 如果欲使用gb2312编码&#xff0c;那么php要输出头&#xff1a;header(“Content-Type: text/html; charsetgb2312")&#xff0c;静态页面添加&#xff0c;所有文件的编码格…

hdfs 多租户_【技术干货】常见的HDFS面试问答精选

最常见的HDFS面试问答1. 什么是HDFS&#xff1f;答&#xff1a;HDFS代表Hadoop分布式文件系统&#xff0c;该系统将大型数据集存储在Hadoop中。它可以在商用硬件上运行&#xff0c;并且具有很高的容错能力。HDFS遵循主/从体系结构&#xff0c;其中许多计算机在集群上运行。群集…

python装饰器常见问题_python 装饰器常见用法

跟踪调用class tracer: # State via instance attributesdef __init__(self, func): # On decoratorself.calls 0 # Save func for later callself.func funcdef __call__(self, *args, **kwargs): # On call to original functionself.calls 1print(call %s to %s % (self…

php通过url传递变量,PHP:如何在模态URL中放置和传递变量

所以,我有一个按钮,可以在同一页面中直接链接到模态.这是按钮和网址href"main_user.php?user_id<?php echo $user[user_id]; ?>#myModal"class"btn btn-warning">(我尝试在#modal之前回显$user_id)是不是&#xff1f;单击按钮后,将出现模态.这…

python 根据类名 查找module_关于 Python 命令中的 m 参数

在命令行中使用 Python 时&#xff0c;它可以接收大约 20 个选项(option)&#xff0c;语法格式如下&#xff1a;python [-bBdEhiIOqsSuvVWx?] [-c command | -m module-name | script | - ] [args]本文想要聊聊比较特殊的“-m”选项&#xff1a;关于它的典型用法、原理解析与发…

php xampp bug,PHP网站访问慢的处理方法

如果网站跑在了LAMP环境中&#xff0c;就无法使用php-fpm的slow log了&#xff0c;那如何分析瓶颈点&#xff1f;没关系你还可以使用这个XdebugWebgrind&#xff0c;其中Xdebug是一个开放源代码的PHP程序调试器(即一个Debug工具)&#xff0c;可以用来跟踪&#xff0c;调试和分析…

matlab安装程序无法启动jvm_JVM 执行 Java 程序时的内存区域划分

在学习 Java 虚拟机(后面简称&#xff1a; JVM )中的垃圾回收机制(GC)之前&#xff0c;先需要了解 在 JVM 中的 Java 程序(class 文件)加载到内存之后到底是怎么存的。在阅读了 JVM规范 和周志明的 《深入理解Java虚拟机(第2版)》 之后&#xff0c;总结一下JVM中的内存划分以及…

phpFpm加载php,php-fpm添加service服务的例子

nginx通过FastCGI运行PHP比Apache包含PHP环境有明显的优势,最近有消息称,PHP5.4将很有可能把PHP-FPM补丁包含在内核里,nginx服务器平台上运行PHP将更加轻松,下面我们就来看一篇php-fpm平滑启动并配置服务例子。我的php是源码安装的。php-fpm在PHP 5.3.2以后的版本不支持以前的p…

python 性能问题_Python 性能问题一直饱受诟病,这篇我们讨论下提升 Python 应用性能的常见方法。...

Python - 提高Python运行效率的六个窍门Python是一门优秀的语言&#xff0c;它能让你在短时间内通过极少量代码就能完成许多操作。不仅如此&#xff0c;它还轻松支持多任务处理&#xff0c;比如多进程。不喜欢Python的人经常会吐嘈Python运行太慢。但是&#xff0c;事实并非如此…

php中没有dockerfile,Dockerfile在RUN composer install命令中没有使用缓...

我以为我已经理解了Docker,但今天我发现了一些关于利用docker缓存的问题.这是我的dockerfileFROM quay.io/my_company/phpjenkinsWORKDIR /usr/src/my_projectADD composer.json composer.jsonADD composer.lock composer.lockRUN composer install -oADD . .RUN mkdir -p temp…

map循环遍历取值_Collection集合框架集和map

Collection集合框架集Java培训之Collection集合框架集MapMap概述Map与Collection并列存在。用于保存具有映射关系的数据:Key-ValueMap 中的 key 和 value 都可以是任何引用类型的数据Map 中的 key 不允许重复key 和 value 之间存在单向一对一关系&#xff0c;即通过指定的 key …

php查询字段前30个字符,php/json我的字段名被截断为30个字符。我能停下来吗?

好吧,我得到了一个供应商软件,他们说应该在ApachePHP服务器和MySQL数据库上运行。我没有这两个,所以我把它放在一个php-iis服务器上,并将代码转换为在SQL服务器上工作。前任。mysql_select_db->mssql_select_db(除其他外)所以我在一个PHP文件中有以下代码$query "SELE…