gpt4 book ai didi

javascript - Node.js 中的事件循环是运行回调本身还是只是将回调传递给调用堆栈以便调用堆栈执行回调?

转载 作者:行者123 更新时间:2023-12-04 10:08:32 25 4
gpt4 key购买 nike

我在学习Node.js并在 Node.js 中遇到了事件循环以及它如何处理异步任务.就我现在的理解,我可能是错的)),例如,当我们使用异步时,比如 fs.readFile()那个readFile将从主线程中取出并传递给 OS kernel (以便内核处理 readFile 而 JS engine 可以继续读取主线程中的其余代码)。然后,曾经kernel已完成 readFile , 事件会被 event loop 接收.所以,问题是在事件被 event loop 接受之后, 事件循环是自己执行回调还是事件循环采用该回调形式队列并将回调传递到调用堆栈中,以便调用堆栈执行该回调?

最佳答案

来自事件循环的回调从头开始,新的和空的调用堆栈。无论当时处于什么调用堆栈中,它早已完成并将控制权返回给事件循环。

回调将以词法上下文记录开始,该记录使回调能够访问适当的词法环境(局部变量等......在定义回调时在范围内),并且在执行之前重新附加到回调。

并且,执行回调将启动一个新的调用堆栈,该堆栈支持回调本身调用其他函数,并使得当回调返回时,控制将返回到事件循环。

仅供引用,调用堆栈只是一个函数返回时返回位置的记录,它被称为堆栈,因为它可以建立然后展开为 a()电话b()然后调用 c()然后返回并返回 b()然后返回并返回 a() .那是堆栈部分。调用栈只是所有这些的存储机制。

由于从事件循环调用的回调在完成后才返回到事件循环,因此在启动回调时调用堆栈上的唯一内容将是返回到事件循环的返回地址。因此,当回调返回时,控制权返回到事件循环。

So, the question is after event was accepted by event loop, will event loop execute BY ITSELF the callback or will event loop takes that callback form queue and passes the callback into call stack in order for the call stack to execute that callback?



这听起来像是一些可能的术语混淆。调用堆栈只是一组存储的返回地址。 JS 解释器使用调用栈来记住返回地址,然后在函数返回时跳转回返回地址。它是运行节目的解释器,而不是运行节目的调用堆栈。调用堆栈只是数据。

所以,假设你有这个代码:
let greeting1 = "Hello";

console.log("AA");

setTimeout(() => {
let greeting2 = "GoodBye";
console.log("A");

fs.readfile('./myfile.txt', () => {
console.log("B", greeting1)
});

console.log("C");
}, 5000);

console.log("BB");

这是带有该代码的事件序列。
  • setTimeout()运行并安排一个回调,从现在开始调用 5 秒。
  • 5 秒后,当 JS 解释器返回到事件循环时,它看到计时器已准备好触发。它调用该超时的回调并附加包含 greeting1 的适当词法记录。这样当回调运行时,它就可以访问 greeting1多变的。事件循环创建一个新的调用堆栈,在其上放置自己的返回地址并调用计时器回调。
  • 定时器回调运行,定义 greeting2 , 输出 console.log("A")并运行 fs.readFile() .
  • fs.readFile()启动异步操作以读取该文件,然后返回。作为其中的一部分,它注册一个要调用的完成回调。
  • 然后console.log("C")执行。定时器回调然后返回到事件循环。
  • 一段时间后,fs.readFile()操作(实际上由多个单独的异步操作组成,但我在这里简化为一个)在文件最终关闭时完成。该文件关闭触发回调以在 fs 中调用模块(在 fs.readFile() 代码内部)。
    事件循环然后类似地创建一个新的调用堆栈,在其上放置自己的返回地址,将适当的词法记录附加到它并调用内部回调 fs模块。当它执行时,它会调用你的回调,你会看到 console.log("B", greeting) 的输出.

  • 控制台输出如下所示:
    AA
    BB
    A
    C
    B, Hello

    Sorry, some questions again, firstly, is it really true that there is OS kernel that handles asynchronous readFile() and once readFile is done, passes the emitted event to event loop? Secondly, so after event loop gets emitted event concerning the completion of readFile(), event loop just calls the callback. But as you can see, all hard was done by OS kernel and event loop just executes the easy part which is callback. So, is it true that even callback can be blocking thus thread pool is used if callback is blocking being hard for event loop?



    不谈 readFile()暂时,因为这是打开文件、执行一次或多次读取然后关闭文件的多阶段操作,这是 Javascript、node.js 中的 native C++ 代码和 OS 库调用的混合。所以,这有点复杂。让我们选择一些类似但更简单的东西。让我们选择一个操作,如 fs.stat()使用此代码:
    fs.stat('./myfile.txt', (stats) => {
    console.log(stats);
    });
    console.log("A");

    以下是步骤:
  • 您拨打 fs.stat() .
  • 这进入了 stat() 的 node.js Javascript 代码称呼。该调用设置了一些上下文以允许将 Javascript 数据传递给 C++ 代码,然后为 stat() 调用 C++ 函数(仍然是特定于 nodejs 的代码,但现在是 C++ 代码)。手术。
  • 然后,C++ 函数准备操作系统调用以获取特定文件的统计信息。但是,它不是在当前线程中执行该调用,这会在运行时阻塞 Javascript 引擎,而是使用 native C++ 线程(从 native 代码线程池获得)并告诉该线程运行 OS 调用。
  • 该线程调用操作系统以获取特定文件的统计信息。
  • 同时,回到第一个收到原始 stat 调用的 C++ 函数中,在它启动线程执行 OS 调用后,它返回到 Javascript。 Javascript stat()操作从 C++ 返回,并返回到您的 Javascript,在那里它继续执行其他 Javascript。
  • 然后它遇到 console.log("A")在上面的代码中并将其输出到控制台。
  • 同时,操作系统正在努力从文件中获取统计信息。当它得到该结果时,它将该结果从线程池返回给线程。然后该线程将事件发布到 nodejs 事件循环。该事件不仅包含 stat 的结果,还包含 Javascript 代码中完成回调所需的上下文。
  • 当事件循环不再做其他事情并且轮到这个事件时,事件循环然后创建正确的 Javascript 上下文(最初与原始 fs.stat() 调用一起传入,设置并调用与那个完成事件。
  • 该回调运行并执行 console.log(stats) .
  • 该回调返回并且控制立即返回到事件循环,在那里它寻找下一个要运行的事件。
  • 关于javascript - Node.js 中的事件循环是运行回调本身还是只是将回调传递给调用堆栈以便调用堆栈执行回调?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61451241/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com