”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > JavaScript 如何在后台工作:了解其单线程性质和异步操作

JavaScript 如何在后台工作:了解其单线程性质和异步操作

发布于2024-12-22
浏览:234

How JavaScript Works in the Background: Understanding Its Single-Threaded Nature and Asynchronous Operations

JavaScript 是网络的支柱,为数十亿网站和应用程序提供动态客户端功能。但您有没有想过 JavaScript 是如何在后台发挥其魔力的?在这篇文章中,我们将深入研究 JavaScript 单线程本质的内部工作原理并探索异步编程的概念。

单线程是什么意思?

当我们说 JavaScript 是“单线程”时,这意味着它有一个调用堆栈。调用堆栈本质上是 JavaScript 跟踪正在执行的函数的结构。它遵循后进先出 (LIFO) 顺序,这意味着最后推送到堆栈的函数将最先完成。以下是其工作原理的示例:

function first() {
    console.log('First function');
}

function second() {
    console.log('Second function');
}

first();
second();

在本例中,first()函数被添加到堆栈并执行。一旦完成,它就会被弹出,第二个()函数被压入堆栈并接下来执行。

虽然单线程语言可能看起来有限,因为它们一次只能做一件事,但 JavaScript 巧妙地使用异步机制使其能够模拟多任务处理。

事件循环和异步执行

JavaScript 使用异步执行来处理可能需要很长时间才能完成的操作,例如网络请求、文件 I/O 或计时器。尽管是单线程的,但由于事件循环和回调队列,它可以同时管理多个任务。

事件循环

事件循环是JavaScript并发模型中的核心概念。它的主要职责是管理 JavaScript 如何处理异步代码执行。其工作原理如下:

  1. 同步代码首先运行。当 JavaScript 启动时,它使用调用堆栈以同步方式逐行执行全局范围内的所有代码。

  2. 异步任务被发送到 Web API(如 setTimeout、fetch 等)或 Node.js API,它们将在后台进行处理。

  3. 回调队列是异步操作完成后放置的地方。

  4. 事件循环不断检查调用堆栈是否为空。如果堆栈为空,它将从回调队列中取出第一项并将其推送到调用堆栈上,以允许其执行。

异步 JavaScript 的魔力在于事件循环、调用堆栈和回调队列之间的交互。异步操作不会阻塞调用堆栈,这意味着 JavaScript 可以在等待后台任务完成的同时继续执行其他代码。

示例:使用 setTimeout

考虑以下带有 setTimeout 函数的示例:

console.log('Start');

setTimeout(() => {
    console.log('This runs after 2 seconds');
}, 2000);

console.log('End');

这是一步一步发生的事情:

  1. JavaScript 打印“Start”。

  2. setTimeout 函数被调用,但不是阻塞执行 2 秒,而是发送到 Web API,在后台运行。

  3. JavaScript 打印“End”,继续执行而不等待 setTimeout 完成。

  4. 2秒后,setTimeout内部的回调函数被放入回调队列中。

  5. 事件循环检查调用堆栈是否为空(确实如此),然后将回调函数推入堆栈并执行它,打印“This running after 2秒”。

Promise 和异步/等待

现代 JavaScript 中处理异步任务的另一种流行方法是通过 Promises 和 async/await 语法,这有助于通过避免深层嵌套的回调(也称为“回调地狱”)来提高代码的可读性。

Promise 表示异步操作的最终完成(或失败)及其结果值。这是一个例子:

const promise = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('Promise resolved!');
    }, 1000);
});

promise.then(result => {
    console.log(result);  // Output after 1 second: 'Promise resolved!'
});

我们可以使用 then() 来处理 Promise 解决时发生的情况,而不是依赖回调。如果我们想以更同步的方式处理异步代码,我们可以使用 async/await:

async function asyncExample() {
    const result = await promise;
    console.log(result);  // Output after 1 second: 'Promise resolved!'
}

asyncExample();

这使得代码更清晰、更容易理解,允许我们在移动到下一行代码之前“等待”异步任务完成,即使 JavaScript 在幕后仍然是非阻塞的。

JavaScript 异步模型中的关键组件

  1. 调用堆栈:执行同步代码的地方。

  2. Web API/Node.js API:处理异步任务(如网络请求)的外部环境。

  3. 回调队列:异步任务结果等待推送到调用栈执行的队列。

  4. 事件循环:在调用堆栈和回调队列之间进行协调的系统,确保任务按正确的顺序处理。

结论

JavaScript 的单线程特性乍一看似乎有局限性,但其异步功能使其能够有效地管理多个任务。通过事件循环、回调队列和 Promises 等机制,JavaScript 能够处理复杂的非阻塞操作,同时保持直观、同步的编码风格。

版本声明 本文转载于:https://dev.to/saiarlen/how-javascript-works-in-the-background-understanding-its-single-threaded-nature-and-asynchronous-operations-5be4?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 如何实时捕获和流媒体以进行聊天机器人命令执行?
    如何实时捕获和流媒体以进行聊天机器人命令执行?
    在开发能够执行命令的chatbots的领域中,实时从命令执行实时捕获Stdout,一个常见的需求是能够检索和显示标准输出(stdout)在cath cath cant cant cant cant cant cant cant cant interfaces in Chate cant inter...
    编程 发布于2025-07-08
  • Java中假唤醒真的会发生吗?
    Java中假唤醒真的会发生吗?
    在Java中的浪费唤醒:真实性或神话?在Java同步中伪装唤醒的概念已经是讨论的主题。尽管存在这种行为的潜力,但问题仍然存在:它们实际上是在实践中发生的吗? Linux的唤醒机制根据Wikipedia关于伪造唤醒的文章,linux实现了pthread_cond_wait()功能的Linux实现,利用...
    编程 发布于2025-07-08
  • 如何处理PHP文件系统功能中的UTF-8文件名?
    如何处理PHP文件系统功能中的UTF-8文件名?
    在PHP的Filesystem functions中处理UTF-8 FileNames 在使用PHP的MKDIR函数中含有UTF-8字符的文件很多flusf-8字符时,您可能会在Windows Explorer中遇到comploreer grounder grounder grounder gro...
    编程 发布于2025-07-08
  • 为什么尽管有效代码,为什么在PHP中捕获输入?
    为什么尽管有效代码,为什么在PHP中捕获输入?
    在php ;?>" method="post">The intention is to capture the input from the text box and display it when the submit button is clicked.但是,输出...
    编程 发布于2025-07-08
  • 哪种方法更有效地用于点 - 填点检测:射线跟踪或matplotlib \的路径contains_points?
    哪种方法更有效地用于点 - 填点检测:射线跟踪或matplotlib \的路径contains_points?
    在Python Matplotlib's path.contains_points FunctionMatplotlib's path.contains_points function employs a path object to represent the polygon.它...
    编程 发布于2025-07-08
  • 如何从PHP中的数组中提取随机元素?
    如何从PHP中的数组中提取随机元素?
    从阵列中的随机选择,可以轻松从数组中获取随机项目。考虑以下数组:; 从此数组中检索一个随机项目,利用array_rand( array_rand()函数从数组返回一个随机键。通过将$项目数组索引使用此键,我们可以从数组中访问一个随机元素。这种方法为选择随机项目提供了一种直接且可靠的方法。
    编程 发布于2025-07-08
  • C++20 Consteval函数中模板参数能否依赖于函数参数?
    C++20 Consteval函数中模板参数能否依赖于函数参数?
    [ consteval函数和模板参数依赖于函数参数在C 17中,模板参数不能依赖一个函数参数,因为编译器仍然需要对非contexexpr futcoriations contim at contexpr function进行评估。 compile time。 C 20引入恒定函数,必须在编译时进行...
    编程 发布于2025-07-08
  • Java中如何使用观察者模式实现自定义事件?
    Java中如何使用观察者模式实现自定义事件?
    在Java 中创建自定义事件的自定义事件在许多编程场景中都是无关紧要的,使组件能够基于特定的触发器相互通信。本文旨在解决以下内容:问题语句我们如何在Java中实现自定义事件以促进基于特定事件的对象之间的交互,定义了管理订阅者的类界面。以下代码片段演示了如何使用观察者模式创建自定义事件: args)...
    编程 发布于2025-07-08
  • 如何高效地在一个事务中插入数据到多个MySQL表?
    如何高效地在一个事务中插入数据到多个MySQL表?
    mySQL插入到多个表中,该数据可能会产生意外的结果。虽然似乎有多个查询可以解决问题,但将从用户表的自动信息ID与配置文件表的手动用户ID相关联提出了挑战。使用Transactions和last_insert_id() 插入用户(用户名,密码)值('test','test...
    编程 发布于2025-07-08
  • 您如何在Laravel Blade模板中定义变量?
    您如何在Laravel Blade模板中定义变量?
    在Laravel Blade模板中使用Elegance 在blade模板中如何分配变量对于存储以后使用的数据至关重要。在使用“ {{}}”分配变量的同时,它可能并不总是最优雅的解决方案。幸运的是,Blade通过@php Directive提供了更优雅的方法: $ old_section =“...
    编程 发布于2025-07-08
  • Java字符串非空且非null的有效检查方法
    Java字符串非空且非null的有效检查方法
    检查字符串是否不是null而不是空的 if(str!= null && str.isementy())二手: if(str!= null && str.length()== 0) option 3:trim()。isement(Isement() trim whitespace whitesp...
    编程 发布于2025-07-08
  • 如何简化PHP中的JSON解析以获取多维阵列?
    如何简化PHP中的JSON解析以获取多维阵列?
    php 试图在PHP中解析JSON数据的JSON可能具有挑战性,尤其是在处理多维数组时。 To simplify the process, it's recommended to parse the JSON as an array rather than an object.To do...
    编程 发布于2025-07-08
  • 在C#中如何高效重复字符串字符用于缩进?
    在C#中如何高效重复字符串字符用于缩进?
    在基于项目的深度下固定字符串时,重复一个字符串以进行凹痕,很方便有效地有一种有效的方法来返回字符串重复指定的次数的字符串。使用指定的次数。 constructor 这将返回字符串“ -----”。 字符串凹痕= new String(' - ',depth); console.Wr...
    编程 发布于2025-07-08
  • 版本5.6.5之前,使用current_timestamp与时间戳列的current_timestamp与时间戳列有什么限制?
    版本5.6.5之前,使用current_timestamp与时间戳列的current_timestamp与时间戳列有什么限制?
    在时间戳列上使用current_timestamp或MySQL版本中的current_timestamp或在5.6.5 此限制源于遗留实现的关注,这些限制需要对当前的_timestamp功能进行特定的实现。 创建表`foo`( `Productid` int(10)unsigned not n...
    编程 发布于2025-07-08
  • MySQL中如何高效地根据两个条件INSERT或UPDATE行?
    MySQL中如何高效地根据两个条件INSERT或UPDATE行?
    在两个条件下插入或更新或更新 solution:的答案在于mysql的插入中...在重复键更新语法上。如果不存在匹配行或更新现有行,则此功能强大的功能可以通过插入新行来进行有效的数据操作。如果违反了唯一的密钥约束。实现所需的行为,该表必须具有唯一的键定义(在这种情况下为'名称'...
    编程 发布于2025-07-08

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3