首页 > 其他分享 >js异步——事件循环和消息队列

js异步——事件循环和消息队列

时间:2023-04-09 14:45:36浏览次数:45  
标签:异步 队列 主线 js 任务 执行

前言

上篇文章中介绍了多进程的浏览器基本架构,现在,我们来谈谈单线程的 JS 代码、消息队列、事件循环、微任务和宏任务。

单线程的 JavaScript

什么是单线程 js?

如果你已经仔细阅读过上一篇文章,那么答案是显而易见的:由于浏览器是由渲染进程的主线程来执行 js 代码的,换句话说,js的运行位置是渲染进程的主线程,所以 js 自然而然就是单线程的。

js 为什么设计成单线程的?

这个问题的答案同样在上一篇文章中有所体现。浏览器中的js执行和页面渲染是在同一个线程中发生的,主线程在解析HTML生成DOM树的过程中,如果遇到<script>标签会先执行js代码而阻塞对HTML的解析,因为 js 能够修改DOM进而影响渲染结果。但如果 js 可以拥有多个线程来执行,那么会出现一边解析HTML进行渲染,一边执行的 js 代码操作 DOM ,这样会影响到页面最终渲染效果的一致性(可预见性)。

同步任务和异步任务

  • 同步任务:按顺序执行的js代码,上一个任务结束才能执行下一个任务,主线程中只执行同步任务
  • 异步任务:不进入主线程执行,而是由宿主环境提供的线程执行。当异步任务完成时,会在消息队列中添加异步任务的回调函数。

消息队列

此时,你可能会有疑问:既然 JS 是单线程的,而异步任务又不是在主线程中执行的,这不是矛盾了吗?实际上,JS的确是单线程,但他的宿主环境(浏览器,Node.js)可不是单线程的,js中一些耗时的任务,可以交由宿主环境的其他线程来执行,但这与多线程语言可以开启多个线程并行执行任务并不相同。

让我们来看看异步任务执行时发生了什么。假设js代码发出了一个异步 http 请求,此时由IO线程来接管执行http请求的代码,主线程将异步任务挂起,并继续执行接下来的同步代码,当IO线程接收到了服务器发来的响应,便将异步任务的回调加入到消息队列的队尾。

消息队列(任务队列)是在主线程之外的数据结构,每当有异步任务完成,那么他的回调函数(callback)就会被push到消息队列的队尾。主线程中所有同步任务执行完之后,由事件循环来通知主线程开始执行消息队列中的任务。

事件循环(Event Loop)

简单的说,事件循环起到通知主线程该执行异步任务回调的作用。每当主线程的同步代码执行完毕后,浏览器变开始进行事件循环,让消息队列的中的队首元素出队,并在主线程中执行,执行完成后,事件循环再次查询消息队列中的队首元素......

事件循环和消息队列相互配合,管理异步任务和它的回调函数。

微任务和宏任务

确切地说,消息队列中的元素是一个一个地宏任务,而宏任务内部有一个微任务队列。js主线程是第一个宏任务。

  • 常见的微任务有:Promise.then(),await 发出的消息,Object.observeprocess.nextTick

  • 常见的宏任务有:主线程所有同步任务、setTimeout的回调、setInterval的回调、setImmediate的回调

    w3c规定:setTimeout() 有一个默认的最小延时时间为4ms,所以即使参数为0,那也是4ms后会将回调函数添加到消息队列

每当一个宏任务的主要任务完成后,事件循环便开始捕获其微任务队列中的微任务,当这个宏任务内的微任务队列为空时,事件循环才开始捕获下一个宏任务和它的微任务队列.....

为什么要分宏任务和微任务?这样的设计是为了给紧急任务一个“插队”的机会,否则新进队列的任务永远放在队尾。可以把微任务理解为更加着急执行的任务,所以可以“插队”,排在宏任务之前被事件循环捕捉。

下面用一组图片来形象地展示消息队列和事件循环、异步任务的运行机制:

没有异步任务时,主线程的一次执行

在主线程中引入事件循环

渲染进程的线程之间发送通知

线程模型:消息队列、事件循环和跨进程发送信息

参考

阿里一面:熟悉事件循环?那谈谈为什么会分为宏任务和微任务。

浅谈浏览器架构、单线程js、事件循环、消息队列、宏任务和微任务

标签:异步,队列,主线,js,任务,执行
From: https://www.cnblogs.com/cpJa3/p/17300303.html

相关文章

  • uniapp如何下载video.js
    在uni-app中引入video.js有两种方式1.通过cdn的方式引入(不建议,当这个cdn失效时,你的业务可能就崩了)<linkhref="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.3.0/video-js.min.css"rel="stylesheet"><scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/vide......
  • js异步——浅谈Chrome浏览器架构
    前言在讲述事件循环和消息队列之前,需要了解JS的单线程执行机制,JS的执行是从上到下依次执行的,这些便是同步任务,而异步操作类似于系统中断,即当前进程外部的实体(主线程之外的、宿主环境提供的、特殊的线程,如IO线程(HTTP请求)和定时器线程等)可以触发代码执行,然后在异步任务完毕后,执......
  • ruoyi-cloud微服务版启动过程报错_20230320版_ Verion 9 of Highlight.js has reached
      Verion9ofHighlight.jshasreachedEOL. Itwillnolonger报错: 这里修改成10.7.3版本D:\2023\qdBigData\RuoYi-Cloud-master\ruoyi-ui>npminstall--registry=https://registry.npm.taobao.org然后到对应目录,再去执行编译去看看.不报错了 >npmrundev然后执行看......
  • Java for Web学习笔记(二六):JSTL(2)Core Tag(上)
    可以在JSP中替代Java代码的几乎所有功能,包括条件编程,循环,迭代和内容输出。taglib的directive如下:<%@taglibprefix="c"uri="http://java.sun.com/jsp/jstl/core"%><c:out>AttributesNameRequiredRequest-timeTypeDescriptionvaluetruetruejava.lang.StringExpression......
  • 第二节:jsx语法深度剖析和jsx本质的探究
    一.        二.        三.         !作       者:Yaopengfei(姚鹏飞)博客地址:http://www.cnblogs.com/yaopengfei/声     明1:如有错误,欢迎讨论,请勿谩骂^_^。声     明2:原创博客请在转载......
  • 龙龙自己写的 JS表格 生成函数
    functiongetTable(tr,td){varnum=1;document.write('<tableborder="1"width="600px">')//vartr=10;for(vari=1;i<=tr;i++){document.write('<tr>')//vartd=10for(varj=1;j<=td;j++){document.......
  • JS事件监听
    事件绑定方式一:通过HTML标签中的事件属性进行绑定<inputtype="button"onclick="on()"value="按钮1"><script>functionon(){alert('我被点击了!')};</script>方式二:通过DOM元素属性绑定<inputtype="button"id="b......
  • JavaWeb-jsp-19课-JSP语法-2023-04-08
    <%@pagecontentType="text/html;charset=UTF-8"language="java"%><html><head><title>$Title$</title></head><body><%--注释JSP带百分号--%><%=newjava.util.Date()%>&l......
  • 同步,异步,阻塞,非阻塞的区别
    同步,异步,阻塞,非阻塞的区别同步与异步同步与异步的重点在消息通知的方式上,也就是调用结果通知的方式;同步:当一个同步调用发出去后,调用者要一直等待调用结果的通知,直到得到调用结果;异步:当一个异步调用发出去后,这个调用就直接返回了,调用者不能立即得......
  • 【算法数据结构专题】「延时队列算法」史上手把手教你针对层级时间轮(TimingWheel)实现
    承接上文承接上一篇文章【算法数据结构专题】「延时队列算法」史上手把手教你针对层级时间轮(TimingWheel)实现延时队列的开发实战落地(上)】我们基本上对层级时间轮算法的基本原理有了一定的认识,本章节就从落地的角度进行分析和介绍如何通过Java进行实现一个属于我们自己的时间轮服务......