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

javascript 同步任务、异步任务,单线程、多线程,执行栈、任务队列、任务队列的维护,宏任务、微任务,事件循环。 原文连接:https://blog.csdn.net/weixin_39788986/article/details/110130711 原文连接:https://blog.csdn.net/terrychinaz/article/details/112425039 阅读详情

在这里插入图片描述

关键词:多进程、单线程、事件循环、消息队列、宏任务、微任务

看到这些词仿佛比较让人摸不着头脑,其实在我们的日常开发中,早就和他们打过交道了。

我来举几个常见的例子:

  • 我执行了一段js,页面就卡了挺久才有响应
  • 我触发了一个按钮的click事件,click事件处理器做出了响应
  • 我用setTimeout(callback, 1000)给代码加了1s的延时,1秒里发生了很多事情,然后功能正常了
  • 我用setInterval(callback, 100)给代码加了100ms的时间轮训,直到期待的那个变量出现再执行后续的代码,并且结合setTimeout删除这个定时器
  • 我用Promise,async/await顺序执行了异步代码
  • 我用EventEmitter、new Vue()做事件广播订阅
  • 我用MutationObserver监听了DOM更新
  • 我手写了一个Event类做事件的广播订阅
  • 我用CustomEvent创建了自定义事件
  • 我·······

其实上面举的这些click, setTimeout, setInterval, Promise,async/await, EventEmitter, MutationObserver, Event类, CustomEvent与多进程、单线程、事件循环、消息队列、宏任务、微任务或多或少的都有所联系。

而且也与浏览器的运行原理有一些关系,作为每天在浏览器里辛勤耕耘的前端工程师们,浏览器的运行原理(多进程、单线程、事件循环、消息队列、宏任务、微任务)可以说是必须要掌握的内容了,不仅对面试有用,对手上负责的开发工作也有很大的帮助。

  • 浅谈浏览器架构
    • 浏览器可以是哪种架构?
    • 如何理解Chrome的多进程架构?
    • 前端最核心的渲染进程包含哪些线程?
      • 主线程(Main thread)(下载资源、执行js、计算样式、进行布局、绘制合成)
      • 光栅线程(Raster thread)
      • 合成线程(Compositor thread)
      • 工作线程(Worker thread)
  • 浅谈单线程js
    • js引擎图
    • 什么是单线程js?
    • 单线程js属于浏览器的哪个进程?
    • js为什么要设计成单线程的?
  • 事件循环与消息队列
    • 什么是事件循环?
    • 什么是消息队列?
    • 如何实现一个 EventEmitter(支持 on,once,off,emit)?
  • 宏任务和微任务
    • 哪些属于宏任务?
    • 哪些属于微任务?
    • 事件循环,消息队列与宏任务、微任务之间的关系是什么?
    • 微任务添加和执行流程示意图
  • 浏览器页面循环系统原理图
    • 消息队列和事件循环
    • setTimeout
    • XMLHttpRequest
    • 宏任务
  • 参考资料

浅谈Chrome架构

浏览器可以是哪种架构?

浏览器本质上也是一个软件,它运行于操作系统之上,一般来说会在特定的一个端口开启一个进程去运行这个软件,开启进程之后,计算机为这个进程分配CPU资源、运行时内存,磁盘空间以及网络资源等等,通常会为其指定一个PID来代表它。

先来看看我的机器上运行的微信和Chrome的进程详情:

软件CPU(%)线程PID内存端口
微信0.146587555MB124301
Chrome7.948481603MB1487

如果自己设计一个浏览器,浏览器可以是那种架构呢?

  • 单进程架构(线程间通信)
  • 多进程架构(进程间IPC通信)

如果浏览器单进程架构的话,需要在一个进程内做到网络、调度、UI、存储、GPU、设备、渲染、插件等等任务,通常来说可以为每个任务开启一个线程,形成单进程多线程的浏览器架构。

但是由于这些功能的日益复杂,例如将网络,存储,UI放在一个线程中的话,执行效率和性能越来越低下,不能再向下拆分出类似“线程”的子空间。

因此,为了逐渐强化浏览器的功能,于是产生了多进程架构的浏览器,可以将网络、调度、UI、存储、GPU、设备、渲染、插件等等任务分配给多个单独的进程,在每一个单独的进程内,又可以拆分出多个子线程,极大程度地强化了浏览器。

如何理解Chrome的多进程架构?

Chrome作为浏览器届里的一哥,他也是多进程IPC架构的。
image

Chrome多进程架构主要包括以下4个进程:

  • Browser进程(负责地址栏、书签栏、前进后退、网络请求、文件访问等)
  • Renderer进程(负责一个Tab内所有和网页渲染有关的所有事情,是最核心的进程)
  • GPU进程(负责GPU相关的任务)
  • Plugin进程(负责Chrome插件相关的任务)

Chrome 多进程架构的优缺点
优点

  • 每一个Tab就是要给单独的进程
  • 由于每个Tab都有自己独立的Renderer进程,因此某一个Tab出问题不会影响其它Tab
    缺点
  • Tab间内存不共享,不同进程内存包含相同内容

Chrome多进程架构实锤图
image

前端最核心的渲染(Renderer)进程包含哪些线程?

image

渲染进程主要包括4个线程:

  • 主线程(Main thread)(下载资源、执行js、计算样式、进行布局、绘制合成)
  • 光栅线程(Raster thread)
  • 合成线程(Compositor thread)
  • 工作线程(Worker thread)

渲染进程的主线程知识点:

  • 下载资源:主线程可以通过Browser进程的network线程下载图片,css,js等渲染DOM需要的资源文件
  • 执行JS:主线程在遇到<script>标签时,会下载并且执行js,执行js时,为了避免改变DOM的结构,解析HTML停滞,js执行完成后继续解析HTML。正是因为JS执行会阻塞UI渲染,而JS又是浏览器的一哥,因此浏览器常常被看做是单线程的。
  • 计算样式:主线程会基于CSS选择器或者浏览器默认样式去进行样式计算,最终生成Computed Style
  • 进行布局:主线程计算好样式以后,可以确定元素的位置信息以及盒模型信息,对元素进行布局
  • 进行绘制:主线程根据先后顺序以及层级关系对元素进行渲染,通常会生成多个图层
  • 最终合成:主线程将渲染后的多个frame(帧)合成,类似flash的帧动画和PS的图层

渲染进程的主线程细节可以查阅Chrome官方的博客:Inside look at modern web browser (part 3)和Rendering Performance

渲染进程的合成线程知识点:

  • 浏览器滚动时,合成线程会创建一个新的合成帧发送给GPU
  • 合成线程工作与主线程无关,不用等待样式计算或者JS的执行,因此合成线程相关的动画比涉及到主线程重新计算样式和js的动画更加流畅

下面来看下主线程、合成线程和光栅线程一起作用的过程
1.主线程主要遍历布局树生成层树
image
2.栅格线程栅格化磁贴到GPU
image
3.合成线程将磁贴合成帧并通过IPC传递给Browser进程,显示在屏幕上
image

图片引自Chrome官方博客:Inside look at modern web browser (part 3)

浅谈单线程js

js引擎图
应用程序(实现)方言和最后版本ECMAScript版本
Google Chrome,V8引擎JavaScriptECMA-262,版本6
Mozilla Firefox,Gecko排版引擎,SpiderMonkey和RhinoJavaScript 1.8.5ECMA-262,版本6
Safari,Nitro引擎JavaScriptECMA-262,版本6
Microsoft Edge,Chakra引擎JavaScriptEMCA-262,版本6
Opera,Carakan引擎(改用V8之前)一些JavaScript 1.5特性及一些JScript扩展[12]ECMA-262,版本5.1
KHTML排版引擎,KDE项目的KonquerorJavaScript 1.5ECMA-262,版本3
Adobe AcrobatJavaScript 1.5ECMA-262,版本3
OpenLaszloJavaScript 1.4ECMA-262,版本3
Max/MSPJavaScript 1.5ECMA-262,版本3
ANT Galio 3JavaScript 1.5附带RMAI扩展ECMA-262,版本3
什么是单线程js?

如果仔细阅读过第一部分“谈谈浏览器架构”的话,这个答案其实已经非常显而易见了。
在”前端最核心的渲染进程包含哪些线程?“这里我们提到了主线程(Main thread)(下载资源、执行js、计算样式、进行布局、绘制合成,注意其中的执行js,这里其实已经明确告诉了我们Chrome中JavaScript运行的位置。

那么Chrome中JavaScript运行的位置在哪里呢?

渲染进程(Renderer Process)中的主线程(Main Thread)

单线程js属于浏览器的哪个进程?

单线程的js -> 主线程(Main Thread)-> 渲染进程(Renderer Process)

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

其实更为严谨的表述是:“浏览器中的js执行和UI渲染是在一个线程中顺序发生的。”

这是因为在渲染进程的主线程在解析HTML生成DOM树的过程中,如果此时执行JS,主线程会主动暂停解析HTML,先去执行JS,等JS解析完成后,再继续解析HTML。

那么为什么要“主线程会主动暂停解析HTML,先去执行JS,再继续解析HTML呢”?

这是主线程在解析HTML生成DOM树的过程中会执行style,layout,render以及composite的操作,而JS可以操作DOM,CSSOM,会影响到主线程在解析HTML的最终渲染结果,最终页面的渲染结果将变得不可预见。

如果主线程一边解析HTML进行渲染,JS同时在操作DOM或者CSSOM,结果会分为以下情况:

  • 以主线程解析HTML的渲染结果为准
  • 以JS同时在操作DOM或者CSSOM的渲染结果为准

考虑到最终页面的渲染效果的一致性,所以js在浏览器中的实现,被设计成为了JS执行阻塞UI渲染型。

事件循环

什么是事件循环?

事件循环英文名叫做Event Loop,是一个在前端届老生常谈的话题。
我也简单说一下我对事件循环的认识:

事件循环可以拆为“事件”+“循环”。
先来聊聊“事件”:

如果你有一定的前端开发经验,对于下面的“事件”一定不陌生:

  • click、mouseover等等交互事件
  • 事件冒泡、事件捕获、事件委托等等
  • addEventListener、removeEventListener()
  • CustomEvent(自定义事件实现自定义交互)
  • EventEmitter、EventBus(on,emit,once,off,这种东西经常出面试题)
  • 第三方库的事件系统

有事件,就有事件处理器:在事件处理器中,我们会应对这个事件做一些特殊操作。

那么浏览器怎么知道有事件发生了呢?怎么知道用户对某个button做了一次click呢?

如果我们的主线程只是静态的,没有循环的话,可以用js伪代码将其表述为:

function mainThread() {
     console.log("Hello World!");
     console.log("Hello JavaScript!");
}
mainThread();

执行完一次mainThread()之后,这段代码就无效了,mainThread并不是一种激活状态,对于I/O事件是没有办法捕获到的。

因此对事件加入了“循环”,将渲染进程的主线程变为激活状态,可以用js伪代码表述如下:

// click event
function clickTrigger() {
    return "我点击按钮了"
}
// 可以是while循环
function mainThread(){
    while(true){
        if(clickTrigger()) { console.log(“通知click事件监听器”) }
        clickTrigger = null;
     }
}
mainThread();

也可以是for循环

for(;;){
    if(clickTrigger()) { console.log(“通知click事件监听器”) }
    clickTrigger = null;
}

在事件监听器中做出响应:

button.addEventListener('click', ()=>{
    console.log("多亏了事件循环,我(浏览器)才能知道用户做了什么操作");
})
什么是消息队列?

消息队列可以拆为“消息”+“队列”。
消息可以理解为用户I/O;队列就是先进先出的数据结构。
而消息队列,则是用于连接用户I/O与事件循环的桥梁。

队列数据结构图

image

入队出队图

image

在js中,如何发现出队列FIFO的特性?

下面这个结构大家都熟悉,瞬间体现出队列FIFO的特性。

// 定义一个队列
let queue = [1,2,3];
// 入队
queue.push(4); // queue[1,2,3,4]
// 出队
queue.shift(); // 1 queue [2,3,4]

假设用户做出了"click button1",“click button3”,"click button 2"的操作。
事件队列定义为:

const taskQueue = ["click button1","click button3","click button 2"];
while(taskQueue.length>0){
    taskQueue.shift(); // 任务依次出队
}

任务依次出队:
“click button1”
“click button3”
“click button 2”

此时由于mainThread有事件循环,它会被浏览器渲染进程的主线程事件循环系统捕获,并在对应的事件处理器做出响应。

button1.addEventListener('click', ()=>{
    console.log("click button1");
})
button2.addEventListener('click', ()=>{
    console.log("click button 2");
})
button3.addEventListener('click', ()=>{
   console.log("click button3")
})

依次打印:“click button1”,“click button3”,“click button 2”。

因此,可以将消息队列理解为连接用户I/O操作和浏览器事件循环系统的任务队列。

如何实现一个 EventEmitter(支持 on,once,off,emit)?

/**
 * 说明:简单实现一个事件订阅机制,具有监听on和触发emit方法
 * 示例:
 * on(event, func){ ... }
 * emit(event, ...args){ ... }
 * once(event, func){ ... }
 * off(event, func){ ... }
 * const event = new EventEmitter();
 * event.on('someEvent', (...args) => {
 *     console.log('some_event triggered', ...args);
 * });
 * event.emit('someEvent', 'abc', '123');
 * event.once('someEvent', (...args) => {
 *     console.log('some_event triggered', ...args);
 * });
 * event.off('someEvent', callbackPointer); // callbackPointer为回调指针,不能是匿名函数
 */

class EventEmitter {
  constructor() {
    this.listeners = [];
  }
  on(event, func) {
    const callback = (listener) => listener.name === event;
    const idx = this.listeners.findIndex(callback);
    if (idx === -1) {
      this.listeners.push({
        name: event,
        callbacks: [func],
      });
    } else {
      this.listeners[idx].callbacks.push(func);
    }
  }
  emit(event, ...args) {
    if (this.listeners.length === 0) return;
    const callback = (listener) => listener.name === event;
    const idx = this.listeners.findIndex(callback);
    if (idx === -1) return;
    const listener = this.listeners[idx];

    if (listener.isOnce) {
      listener.callbacks[0](...args);
      this.listeners.splice(idx, 1);
    } else {
      listener.callbacks.forEach((cb) => {
        cb(...args);
      });
    }
  }
  once(event, func) {
    const callback = (listener) => listener.name === event;
    let idx = this.listeners.findIndex(callback);
    if (idx !== -1) return;
    this.listeners.push({
      name: event,
      callbacks: [func],
      isOnce: true,
    });
  }
  off(event, func) {
    if (this.listeners.length === 0) return;
    const callback = (listener) => listener.name === event;
    let idx = this.listeners.findIndex(callback);
    if (idx === -1) return;
    let callbacks = this.listeners[idx].callbacks;
    for (let i = 0; i < callbacks.length; i++) {
      if (callbacks[i] === func) {
        callbacks.splice(i, 1);
        break;
      }
    }
  }
}

// let event = new EventEmitter();
// let onceCallback = (...args) => {
//   console.log("once_event triggered", ...args);
// };
// let onceCallback1 = (...args) => {
//   console.log("once_event 1 triggered", ...args);
// };
// // once仅监听一次
// event.once("onceEvent", onceCallback);
// event.once("onceEvent", onceCallback1);
// event.emit("onceEvent", "abc", "123");
// event.emit("onceEvent", "abc", "456");

// let onCallback = (...args) => {
//   console.log("on_event triggered", ...args);
// };
// let onCallback1 = (...args) => {
//   console.log("on_event 1 triggered", ...args);
// };
// event.on("onEvent", onCallback);
// event.on("onEvent", onCallback1);
// event.emit("onEvent", "abc", "123");
// // off销毁指定回调
// event.off("onEvent", onCallback);
// event.emit("onEvent", "abc", "123");

宏任务和微任务

  • 哪些属于宏任务?
  • 哪些属于微任务?
  • 事件循环,消息队列与宏任务、微任务之间的关系是什么?
  • 微任务添加和执行流程示意图
哪些属于宏任务?
  • setTimeout
  • setInterval
  • setImmediate
  • requestAnimationFrame
  • I/O
  • UI渲染
哪些属于微任务?
  • Promise
  • MutationObserver
  • process.nextTick
  • queueMicrotask
事件循环,消息队列与宏任务、微任务之间的关系是什么?
  • 宏任务入队消息队列,可以将消息队列理解为宏任务队列
  • 每个宏任务内有一个微任务队列,执行过程中微任务入队当前宏任务的微任务队列
  • 宏任务微任务队列为空时才会执行下一个宏任务
  • 事件循环捕获队列出队的宏任务和微任务并执行

事件循环会不断地处理消息队列出队的任务,而宏任务指的就是入队到消息队列中的任务,每个宏任务都有一个微任务队列,宏任务在执行过程中,如果此时产生微任务,那么会将产生的微任务入队到当前的微任务队列中,在当前宏任务的主要任务完成后,会依次出队并执行微任务队列中的任务,直到当前微任务队列为空才会进行下一个宏任务。

微任务添加和执行流程示意图

假设在执行解析HTML这个宏任务的过程中,产生了Promise和MutationObserver这两个微任务。

// parse HTML···
Promise.resolve();
removeChild();

微任务队列会如何表现呢?

image

image

图片引自:极客时间的《浏览器工作原理与实践》

过程可以拆为以下几步:

  1. 主线程执行JS Promise.resolve(); removeChild();
  2. parseHTML宏任务暂停
  3. Promise和MutationObserver微任务入队到parseHTML宏任务的微任务队列
  4. 微任务1 Promise.resolve()执行
  5. 微任务2 removeChild();执行
  6. 微任务队列为空,parseHTML宏任务继续执行
  7. parseHTML宏任务完成,执行下一个宏任务

浏览器页面循环系统原理图

以下所有图均来自极客时间《《浏览器工作原理与实践》- 浏览器中的页面循环系统》,可以帮助理解消息队列,事件循环,宏任务和微任务。

  • 消息队列和事件循环
  • setTimeout
  • XMLHttpRequest
  • 宏任务
消息队列和事件循环

线程的一次执行
image
在线程中引入事件循环
image
渲染进程线程之间发送任务
image

image
线程模型:队列 + 循环
image
跨进程发送消息
image
单个任务执行时间过久
image

setTimeout

长任务导致定时器被延后执行
image
循环嵌套调用 setTimeout
image

XMLHttpRequest

消息循环系统调用栈记录
image
XMLHttpRequest 工作流程图
image
HTTPS 混合内容警告
image
使用 XMLHttpRequest 混合资源失效
image

宏任务

宏任务延时无法保证
image

参考资料

  • https://www.infoq.cn/article/CS9-WZQlNR5h05HHDo1b
  • https://developers.google.com/web/updates/2018/09/inside-browser-part3
  • https://juejin.im/post/6844903561164242952
  • https://time.geekbang.org/column/article/132931
  • https://segmentfault.com/a/1190000012925872
  • https://zh.wikipedia.org/wiki/JavaScript%E5%BC%95%E6%93%8E

如果文中有不对的地方,欢迎指正和交流~

期待和大家交流,共同进步,欢迎大家加入我创建的与前端开发密切相关的技术讨论小组:

努力成为优秀前端工程师!

ROS四旋翼无人机快速上手指南(4):阿木实验室PX4功能包飞行控制分析与讲解(重点章节) 成就更好的自己 这一章详细讲解一下阿木实验室(AMOV)的开源项目px4_command功能包,此功能包通过mavlink协议直接控制烧录px4固件的自驾仪,还融合了来自各个传感器的位姿,距离等信息,此外,功能包提供的接口向上对接应用层算法级的程序例如SLAM,kfc目标检测引导,路径规划等算法,因此,在整个无人机控制中起到了承上启下至关重要的作用。 用到的文件及工具包链接如下: AMOV实验室源码如下: https://gitee.com/theroadofengineers/px4_comman 阅读详情

相关推荐

llama.cpp量化模型在MTT显卡上的性能对比:S80/S3000/S4000实测数据

本文基于摩尔线程MTT S80、S3000和S4000三款显卡,对llama.cpp量化模型进行了深度性能实测。报告详细对比了不同量化精度(如Q4_K_M、Q6_K)在Llama 3.2 1B和Qwen 2.5 7B模型上的推理速度、显存占用、功耗及温度表现,为开发者根据硬件选择最优模型配置与参数调优提供了关键数据参考和实战指南。

week9的博客 350

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

作者:趁你还年轻转发链接:https://segmentfault.com/a/1190000022950333前言看到这些词仿佛比较让人摸不着头脑,其实在我们的日常开发中,早就和它们打过交道了。我来举几个常见的例子:我执行了一段js,页面就卡了挺久才有响应我触发了一个按钮的click事件,click事件处理器做出了响应我用setTimeout(callback, 1000)给代码加了1s的延时,...

weixin_39770626的博客 516

论文理解【LLM-Clarification】—— 【QDrawer】Asking the Right Question at the Right Time: Human and Model Unce

本文基于 CoDraw 任务对 LLM 澄清提问的触发方式进行探索,发现模型内部不确定性与人类澄清决策相关性弱,使用不确定性阈值触发澄清提问相比模仿人类提问时机,性能和计算效率都更好

佚失的诗篇 770

js中断后续执行的几种方法

我们看到在testD中调用了testC,在testC中想通过return把alert(‘d’);也终止了,事与愿违return只终止了testC,程序执行会依次弹出’c’,‘d’。两个函数做了修改,testC中返回false,testD中对testC的返回值做了判断,这样终止testC的同时也能将testD终止,程序执行弹出’d’便会终止。以上是常规的中断执行方法,那么函数调用函数如何在嵌套的函数里面中断执行呢?程序执行会依次弹出’a’,‘b’,‘c’。(二)非function方法里面。

张木期的博客 4628

STM32H743的ADC还能这么玩?定时器触发+DMA搬运,构建低CPU占用的数据流

本文深入探讨了STM32H743微控制器中ADC的高效使用方法,通过定时器触发和DMA搬运技术实现低CPU占用的数据流采集。详细解析了硬件架构、CubeMX配置步骤及高级优化技巧,包括双缓冲技术和多ADC同步采样,适用于电机控制、音频采集等高性能应用场景。

weixin_30698527的博客 647

毕业论文管理系统的设计与实现

毕业论文工作是高等学校本科培养阶段的一个重要环节。目前论文管理工作存在着许多问题,例如人工管理极为不便;学生对论文所要撰写的内容并不十分了解,与指导老师的沟通非常不便;老师的指导监督也很难完全到位;手工评审的效率低等。而现有的一些毕业论文信息管理或答辩评审系统只是实现了部分网上交流和评审管理的功能,在答辩评审的自测和项目指标权重等方面都存在着一定的不足。因此,本文设计的毕业论文管理系统采用B/S模式开发。其中,Browser层使用JSP技术开发;

wqq_992250277的博客 3182

关于在vue项目中,刷新页面时websocket断开连接的解决办法

Vue作为一个单页面应用, webSocket可以说是用起来非常爽了. 因为webSocket在同一个html文件中,是可以保持连接的. 但是当使用f5或者点击刷新页面以后, websocket连接就会强制关闭. 关于这个问题我研究了很久,最后找到两种解决办法;先说下我踩过的坑,起初我设想,在登录并创建websocket连接成功后,设置一个字段保存在localStorage或者cookie中: w...

阿周的博客 4万+

正版63棋牌源代码游戏+728游戏全套带前端源代码解析

这俩天抽时间仔细看了一下这套项目包含完整的前端、后端及后台管理系统。从上传的截图可以看出,前端基于资源目录,后端采用和,后台管理界面提供数据查询与管理功能。本篇文章将从前端结构、后端接口、数据库设计、常见 BUG 及优化方法等方面逐步拆解,并给出相应的代码示例和实践经验。

aa2031171的博客 3572

WebSocket 经常断开原因,解决办法:心跳机制防止自动断开连接。

WebSocket断开原因、给人一种经常掉线的感觉。 1、断开原因 WebSocket断开的原因有很多,最好在WebSocket断开时,将错误打印出来。 ws.onclose = function (e) { console.log('websocket 断开: ' + e.code + ' ' + e.reason + ' ' + e.wasClean) console.log(e) } 错误状态码: WebSocket断开时,会触发CloseEvent, CloseEvent会.

CaiXinXing的优快云博客 6万+

Graphviz安装及使用:决策树可视化

Python大数据分析与机器学习学习笔记 Graphviz安装及使用:决策树可视化

算法工程师 1万+

14、多层螺旋 CT 技术详解

本文详细解析了多层螺旋CT(MSCT)技术的原理与应用,涵盖其相对于单层螺旋CT的优势,包括图像采集速度提升、分辨率提高和噪声降低。文章深入探讨了扫描仪的几何结构、离散投影模型以及关键参数如切片宽度和螺距的影响,并重点介绍了z-滤波重建算法及其离散实现流程。通过流程图和公式推导,系统梳理了从投影获取到图像重建的全过程。同时分析了MSCT在临床中的实际应用案例及未来发展趋势,如更高分辨率、更低辐射剂量和智能化算法等方向,全面展示了MSCT在现代医学影像中的核心价值。

f0g1h2的博客 194

浏览器原理:6.3宏任务和微任务

前面提到,浏览器的消息队列用来存储各个进程/线程向渲染主线程发送的事件,但因为有些事件的优先级是比较高的,而消息队列只能按顺序来无法满足优先级这一需求,为了满足优先级这个需求,于是微任务应运而生,微任务可以理解成是消息队列中的一种任务类型,消息队列中存放着来自若干个任务,这些任务都存在着各自的特点,于是按照一定的归类来讲各个任务分类。宏任务和微任务就是其中的两种任务类型。 宏任务和微任务宏任务微任务异步代码在JS引擎中的两种执行情况微任务的执行机制 宏任务 宏任务包括但不限于 渲染事件 用户交互事件(比如

qq_51005544的博客 1177

二、FM1288调试方案-工具软件使用

分析音频数据的软件需要满足以下几点:1、能打开原始pcm音频文件;2、基本的音频播放软件的操作;3、能查看分析音频数据的频率成分;4、能查看分析音频音量幅度;5、能完成基本音频处理:降噪、音量增幅限幅、滤波和均衡;

优快云mianfeixiazai001的博客 1294

js 单线程、宏任务与微任务的区别以及执行顺序是什么

宏任务:指消息队列中的等待被主线程执行的事件宏任务执行时都会重新创建栈,然后调用宏任务中的函数,栈也会随着变化。但宏任务执行结束时,栈也会随之销毁。微任务:可以看成是一个需要异步执行的函数微任务是基于消息队列、事件循环、UI 主线程还有堆栈而来的微任务的执行时机:在主函数执行结束之后、当前宏任务结束之前。

小草莓的博客 3366

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

JavaScript 深入解析:同步、异步、微任务、宏任务、消息队列与事件循环

4.定时器触发线程5.http异步线程6.EventLoop(事件循环)处理线程js是单线程的,也就是说,同一个时间只能做一件事在上面的例子中,所有代码都是同步执行的,longRunningTask会阻塞后续代码的执行,知道它完成,为了解决单线程带来的阻塞问题,js引入了异步编程模型。

m0_63472757的博客 1267

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

详解宏任务、微任务与事件循环 Event Loop

事件循环 Event Loop,是指浏览器或Node的一种解决javaScript单线程运行时“非阻塞”的一种机制,也就是我们经常使用异步的原理。本文会带你吃透“事件循环”,掌握底层原理,轻松应对JavaScript执行机制问题~

圆圆的 JavaScript 博客 2589

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

ajax请求是宏任务还是微任务_一篇搞定(Js异步、事件循环与消息队列、微任务与宏任务)...

前言 我们都知道javascript是一门单线程、异步、非阻塞、解析类型脚本语言。单线程 ??异步 ??非阻塞 ??然后还有 事件循环、消息队列,还有微任务、宏任务这些这几天在掘金、知乎等论坛翻阅了不少大佬的文章,似乎了解到了一二,然后在这里把自己的体会总结出来,帮助大家快速理解,也能增加自己的记忆。单线程与多线程 JavaScript 的设计就是为了处理浏览器网页的交互(DOM操作的处...

weixin_39788986的博客 3111

JS的同步和异步、微任务和宏任务

1.为什么JS是单线程的 js是运行于浏览器的脚本语言,因其经常涉及操作dom,如果是多线程的,如果一个线程修改dom,另一个线程删除dom,那么浏览器就不知道该先执行哪个操作,所以js执行的时候会按照一个任务一个任务来执行,那么任务是怎么排列的呢 2.为什么JS的任务要分类为同步任务和异步任务 试想一下,如果js的任务都是同步的,那么遇到定时器、网络请求等这类型需要延时执行回调函数的任务会发生什么?页面会像瘫痪一下暂停下来等待这些需要需要时间的代码执行完毕,基于此,又引入了异步任务,每个异步任务都必

titoni_yunruohan的博客 2445

什么是javascript的事件循环

本篇讲解什么是javascript的事件循环,事件循环的运行机制和执行顺序,理解事件循环对于编写高效、流畅的 JavaScript 代码至关重要。

Sherry Tian的博客 1973

浏览器视角看 —— 消息队列和事件循环、宏任务和微任务

JavaScript 是一门单线程的语言,这意味着它在同一时间只能做一件事。为了管理异步行为,JavaScript 引入了事件循环(Event Loop)的概念。事件循环是JavaScript引擎的核心组件之一,它负责管理JavaScript的执行流程,包括同步代码的执行和异步回调的调度。通过本文的讲解,我们深入了解了JavaScript的消息队列和事件循环机制,以及宏任务和微任务的区别和执行顺序。理解这些核心概念有助于我们写出更高效、更可靠的代码,并且能够在实际开发中有效地处理各种异步问题。

一个做过前端开发的产品经理,经历过睿智产品的折磨导致脱发之后,励志要翻身"农奴"把歌唱,一边打入敌人内部一边持续提升自己,为我们广大开发同胞谋福祉,坚决抵制睿智产品折磨我们码农兄弟! 822

JS的事件循环(Event Loop)以及宏任务和微任务

JS的事件循环(Event Loop)以及宏任务和微任务

呆呆狗 1198

JavaScript 中线程、事件循环、消息队列、宏任务、微任务

JavaScript 中线程、事件循环、消息队列、宏任务、微任务

m0_66333906的博客 1075

事件循环:JavaScript 异步编程的幕后功臣

JavaScript 通过事件循环和消息队列实现了异步编程的能力,允许在单线程环境中有效处理多个操作。理解事件循环和消息队列的机制,对于写出高效的 JavaScript 代码、处理复杂的异步流程至关重要。通过合理使用这些机制,可以提高程序的响应速度和用户体验。

你若盛开,清风自来 2078

简述事件循环(event loop)、微任务、宏任务

简述事件循环(event loop)、宏任务、微任务首先明白以下几点:JS为什么是单线程的?JS为什么需要异步?JS单线程又是如何实现异步的呢?浏览器的多线程javaScript 的事件循环(event loop)宏任务微任务事件循环流程事件循环图示示例参考文章 首先明白以下几点: JS为什么是单线程的? js作为主要运行在浏览器的脚本语言,js主要用途之一是操作DOM。假如有两个线程,多线程的...

Waifang 2401

宏任务和微任务、事件循环、面试题

事件循环比较简单,它是一个在 “JavaScript 引擎等待任务”,"执行任务"和"进入休眠状态等待更多任务"这几个状态之间转换的无限循环。

小陈的博客 2017

JavaScript异步、事件循环和消息队列、宏任务和微任务

“JavaScript定位:单线程、异步、非阻塞、解释型脚本语言。” 曾经被问过一个问题:js 是单线程,为什么会有异步代码执行? 为什么是单线程?JavaScript的设计就是为了处理浏览器网页间的交互(DOM操作的处理、UI动画等),如果有多个线程同时操作DOM,那么网页会是一团糟。 ...

cjx1259972299的博客 759
上一篇: 发现数据结构之美-栈
下一篇: 2020年冬季前端笔试题总结
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

趁你还年轻233

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值