• 作者:老汪软件技巧
  • 发表时间:2024-12-27 10:06
  • 浏览量:

全文没有特殊提及的引擎外均为V8引擎

V8是运行时环境,这个相信大家一定清楚。

为了获得速度,V8将JavaScript代码转换为更高效的机器代码,而不是使用解释器。它通过使用JIT(Just-In-Time)编译器(注意:JIT编译器是一部分编译器的类别,并非一个编译器的名字),在执行时将JavaScript代码编译为机器代码。V8不生成字节码或任何中间代码。

V8引擎在内部是多个线程的:

V8由两方面组成:

每一个进入调用栈的都称为调用帧,因为JavaScript是单线程的,运行代码很容易,不必处理多线程环境中出现的复杂场景,例如死锁,但是在一个线程上运行也会非常受限制。

实际上是可以同步实现Ajax请求的,如下代码示例:

function fetchDataSync(url) {
  const xhr = new XMLHttpRequest();
  xhr.open('GET', url, false); 
  xhr.send();
​
  if (xhr.status === 200) {
    return JSON.parse(xhr.responseText);
  } else {
    throw new Error(`HTTP error! status: ${xhr.status}`);
  }
}
try {
  const data = fetchDataSync('https://xxx.com');
  console.log('Fetched data:', data);
} catch (error) {
  console.error('Error:', error);
}

协作进程__高效的协作机制

尽管JavaScript允许异步的代码(就像是我们刚刚说的setTimeout) ,但直到ES6,JavaScript自身从未有过任何关于异步的直接概念。

能够运行JavaScript的环境(浏览器、Nodejs等等)都拥有一个事件循环的内置机制, JS引擎只是任意的JS代码按需执行的环境。是它周围的环境来调度这些事件(JS代码执行)。

事件循环的核心职责为:监听事件、调度任务和协调执行

因此,JavaScript引擎只负责执行代码,何时执行、执行什么代码是由运行环境的事件循环机制决定的。

举个形象一点的例子:

比如:

一个定时器setTimeout被设置,宿主环境记录定时器,并在到达时间后,将其回调函数加入任务队列。事件循环监控任务队列,一旦主线程空闲,就从队列中取出回调,交给JavaScript引擎执行。

image-20241210205906874.png

我这里有一段代码:

setTimeout(fun(), 1000)

这个代码替换掉上图代码块中的代码,执行结果仍然是一致的,但是要强调这并不意味着fun()会在1s后执行,而是意味着在1s过后fun()会在事件循环的控制下,放入事件队列中。放入事件队列中就意味着会被立即执行?当然不是!这个队列中可能会错开时间优先执行更早被添加到事件队列的事件,你的fun()会按照顺序等待执行。

在ES6中新引入了一种概念叫做作业队列(Job Queue),这个通常在现今被称为微任务队列(与之相对的是宏任务队列)。微任务队列是JS引擎管理的一种高优先级异步任务队列,用于存放Promise的回调或者一些特定的异步任务(async/await的后续代码,queueMicotask等)。

常见的宏任务:

常见的微任务就宽泛的理解为异步任务吧!

通常一个宏任务会伴随着一个微任务队列,这说明通常宏任务是和微任务交替进行工作的,两者分别在引擎和宿主环境中通过事件循环机制紧密协作。

微任务队列的优先级是高于宏任务队列的,所以他们的执行时机就是主进程执行完同步任务后,立即清空微任务队列中的内容,将其放入调用栈执行,一个宏任务执行完成后,再清空微任务...直至任务队列中没有任务

image-20241210211634301.png

微任务队列不需要经过Web APIs,而是直接进入微任务队列,由引擎在当前事件循环结束时清空。这与宏任务不同,宏任务的许多来源通常是由浏览器或Node.js的API提供支持。

上面提到了,JS引擎实际上不具有事件循环的机制,这就意味着通常是宿主环境对任务队列进行管理细分(例如宏任务队列和微任务队列)。

在Chrome浏览器中,宏任务队列由Chrome的Blink引擎管理,而微任务由V8引擎管理。

JavaScript的运行机制就像一场精心编排的舞台剧——V8引擎是演员,事件循环是导演,宏任务和微任务则是按照剧本安排出场的角色。每一次代码执行,都是一场充满默契的协作表演。所以,下次当你写setTimeout或Promise时,不妨想象自己正在排演一场舞台剧。谁会先登场,谁又会压轴出场,关键就看你的“导演”如何调度!想要成为这场大戏的主导者,深入理解这些机制,就是你手握话筒的第一步:)


上一条查看详情 +事件代理:借助事件流机制的巧妙实现
下一条 查看详情 +没有了