JavaScript异步性和运行时

JavaScript异步性和运行时,javascript,asynchronous,Javascript,Asynchronous,我已经读了很多关于异步JavaScript的书,但是我仍然不能完全理解它 据我所知,异步JavaScript只是为异步操作编写处理程序。异步操作(不是JS引擎的一部分)然后在一个单独的线程上运行该操作,将回调移动到消息(回调)队列中,最后将回调推送到调用堆栈,由JS引擎执行 除了异步操作在完成后“神奇地”执行回调之外,我还应该更多地了解异步操作吗?(通过“神奇地”完成上述过程) 例如,我所知道的是,setTimeout()函数accepts是异步的,它接受回调和以毫秒为单位的时间,而与它的实际工

我已经读了很多关于异步JavaScript的书,但是我仍然不能完全理解它

据我所知,异步JavaScript只是为异步操作编写处理程序。异步操作(不是JS引擎的一部分)然后在一个单独的线程上运行该操作,将回调移动到消息(回调)队列中,最后将回调推送到调用堆栈,由JS引擎执行

除了异步操作在完成后“神奇地”执行回调之外,我还应该更多地了解异步操作吗?(通过“神奇地”完成上述过程)

例如,我所知道的是,
setTimeout()
函数accepts是异步的,它接受回调和以毫秒为单位的时间,而与它的实际工作方式无关

因此,作为一名JavaScript开发人员,我应该不担心JS运行时如何使函数异步的整个过程吗

我是否需要处理消息队列或事件循环本身的实现,或者“神奇的”异步操作总是由运行时提供


还是我误解了什么?

异步可以涵盖诸如用户单击按钮、代码块在特定时间后排队运行的超时、代码块计划在每个特定时间间隔运行的时间间隔以及对数据的请求,其中对服务器的调用将在不确定时间后响应。这确实是一个比StackOverflow问题更大的话题。但是,请阅读事件处理程序、承诺以及如果您真的想要一些重东西RxJs


大多数开发人员永远不需要完全理解运行时是如何实现这些功能的,只需要很好地理解如何使用它们。

我同意Adrian的观点,异步编程是StackOverflow中要讨论的一个相当有缺陷的主题,因此我将分享一些资源来研究和理解这些概念

它们相当多,而且相当重,但值得一读/一看,因为
异步性
是JS编程的基本和最重要的方面之一

这些视频/帖子大多详细介绍了JavaScript中异步和“并发”的底层机制(如事件循环)

我希望,在观看/阅读这些资源后,您能够掌握这些概念并获得深入理解


另外,如果你渴望获得更多关于
async
JS编程的资源,你可以看看我收集的链接,当你说“创建一个对象并将属性x设置为y”时,你会停下来思考JS运行时如何在内存中表示对象吗?在数字
2
中添加一个字符串
“1”
怎么样?运行时如何处理类型强制

您对
setTimeout
的理解是使用它所需要的全部。对于
函数*
承诺
异步
/
等待
也是如此。JS运行时如何使这些成为可能并不重要。你只需要按计划把这些部件连接起来


也就是说,随着时间的推移,更好地理解它们将对您有所帮助。通过利用运行时的优势,您可以编写更好、更快的程序,但这是入门所必需的。

您真的需要停止一切都与线程有关的想法。javascript中几乎所有的异步操作都在主线程上执行

注意:有人会告诉你这是错误的,javascript使用多线程,并指向node.js文档中有关V8的内容。我告诉你他们错了。Node.js确实会运行额外的线程,但它们仅用于磁盘I/O(所有磁盘I/O都在一个磁盘I/O线程上执行,而不是每个文件一个线程)、DNS(因为DNS API被阻塞)、加密函数(因为它使用CPU而不是I/O)和zip压缩(与加密的原因相同)。其他一切,包括网络I/O、鼠标和键盘处理、设置超时等,都不要在单独的线程上运行。您可以在节点自己关于事件循环的文档中阅读有关此的更多信息:

javascript中的异步代码主要指C程序员所称的非阻塞I/O。阻塞I/O会停止进程,直到数据可用:

// Blocking I/O pseudocode
data = read(file);
非阻塞I/O立即返回,不返回可用数据。而是开始提取数据的过程:

// Non-blocking I/O (javascript's internal asynchronous) pseudocode
beginReading(file);

while (waiting) {
   if (readyToRead(file)) {
       data = read(file);
   }
}
与阻塞I/O相比,非阻塞I/O的优势在于,当操作系统告诉设备驱动程序从文件中提取一些字节时,设备驱动程序开始PCI事务,PCI总线与磁盘控制器通信,磁盘控制器开始在存储介质上进行寻址操作。。当所有这些都发生时(这在CPU时间上是一个很长的时间)。。您可以执行以下代码:

// Blocking I/O pseudocode
data = read(file); // several million instructions could have been executed
                   // but our process is blocked waiting for data

// Non-blocking I/O (javascript's internal asynchronous) pseudocode
beginReading(file);

while (waiting) {
   if (readyToRead(file)) {
       data = read(file);
   }
   else {
       executeMoreCode(); // continue processing javascript while waiting
   }
}
在C/C++中,大多数人都会硬编码(就像在中一样,实际上是编写上面的
executemrecode()
),除非他们习惯于使用函数指针(语法非常糟糕)。即便如此,C/C++在编译程序后,也没有提供一种简单的方法来重新定义这个函数(聪明的人可以用接口来创造奇迹——考虑在Windows编译后可以加载的打印机驱动程序——但是它仍然很复杂)。 Javascript具有一级函数,因此大多数Javascript API允许您将回调作为参数传递给启动非阻塞请求的函数调用

在内部,javascript就是这样做的:

// pseudocode:
do {
    eventHandlers = executeJavascript();
    // end of execution

    events = waitForAllIO(); // this actually blocks but it is waiting
                             // for ALL I/O instead of just one

    if (events.timeout) {
        foreach (callback from eventHandlers) {
            if (callback is TIMEOUT_HANDLER) {
                callback(events.timeout);
            }
        }
    }
    else {
        foreach (event from events) {
             foreach (callback from eventHandlers) {
                 if (callback is for event) {
                     callback(event);
                 }
             }
        }
    }
} while (eventHandlers.length > 0)
这个循环有很多名字。Adobe Flash(与node.js类似,它是一种与浏览器javascript略有不同的ECMAScript语言)将其称为“弹性跑道”。大多数人只是称之为事件循环

正如你所说