学习链接
Event Loops in NodeJS – Beginner's Guide to Synchronous and Asynchronous Code (freecodecamp.org)
- 作者:Tejan Singh
译文
NodeJS是一个异步事件驱动的JavaScript运行环境,旨在建立可扩展的网络应用。
这里的异步指的是JavaScript中所有那些在后台处理而不阻断任何其他请求的函数。
在这篇文章中,你将学习和了解NodeJS是如何工作的,以及如何处理同步或异步发送到服务器的所有功能或请求。
什么是事件循环?
Node使用NodeJS环境中的事件循环来处理请求。但首先,让我们了解一些基本术语,这将有助于我们理解整个机制。
一个事件循环是一个事件监听器,它在NodeJS环境中发挥作用,并随时准备监听、处理和输出一个事件。
事件可以是任何东西,从鼠标点击到按键或超时。
什么是同步和异步编程?
同步编程意味着代码按其定义的顺序运行。在一个同步程序中,当一个函数被调用并返回了一些值后,才会执行下一行。
让我们通过这个例子来理解。
在这个例子中,当listItems(items)函数被调用时,它将循环浏览数组中的项目。
- console.log(item)函数首先对数组的第一个项目被调用,并打印出 "Buy milk"。
- 然后再次执行console.log(item),这次它通过数组中的第二项并打印出 "Buy coffee"。
所以你可以说,函数是按照它被定义的顺序执行的。
另一方面,异步编程是指不按顺序执行的代码。这些功能不是按照它们在程序内定义的顺序执行,而是在满足某些条件时才执行。
例如,setTimeOut()在延迟一定数量的毫秒后执行一项任务。
这些函数并不逐行运行,而只是在需要运行的时候才运行,与函数的声明无关。在这种情况下,当所有的同步函数都被执行后,该函数会在3秒后自动运行。
注意:异步函数只有在所有同步函数被执行后才会运行和执行。在此之前,它们将在后台被处理。
但是,NodeJS如何在后台处理异步函数并先运行所有同步函数?
- 所有这些机制都可以用NodeJS的事件循环轻松解释。
事件循环是如何工作的?
现在让我们看看NodeJS事件循环如何使用Nodejs事件循环图来执行一个简单的同步程序。然后,我们将研究Node是如何逐行执行程序的。
在左上角,你有一个将被执行的Node文件。在左下方,你有一个程序的输出终端。然后,你有调用堆栈、Node APIs和回调队列。所有这些共同构成了NodeJS的环境。
对于同步编程,你只需要关注调用栈。这是NodeJS环境中唯一会在这种情况下工作的部分。
回调栈是一个数据结构,你用它来跟踪将在程序内部运行的所有函数的执行情况。这个数据结构只有一个开口端,可以添加或删除顶部的项目。
当程序开始执行时,它首先被包裹在一个匿名的main()函数中。这是由NodeJS自动定义的。所以main()首先被推送到回调栈中。
接下来,变量a和b被创建,它们的总和被存储在一个变量sum中。所有这些值都存储在内存中。
现在,console.log()是一个被调用并推到回调栈内的函数。它被执行,你可以在终端屏幕上看到输出。
在这个函数被执行后,它被从回调栈中删除。然后main()也被删除,因为程序中没有任何东西可以被调用。这就是一个同步程序的执行方式。
现在,让我们看看异步函数或程序如何在NodeJS内部执行。我们需要回调栈、Node API和回调队列一起处理一个异步函数。
让我们先来看看这个例子。
像往常一样,当程序开始执行时,
- 首先main()函数被添加到回调栈中。
- 然后,console.log("Start")被调用并被添加到回调栈中。
- 在处理之后,输出在终端上是可见的,然后它被从回调栈中删除。
现在,接下来是setTimeOut(...Zero...)函数,它被添加到回调栈中。
由于这是一个异步函数,
- 先添加到回调栈中。
- 但是不会在回调栈中得到处理。
- 从回调栈中添加到Node APIs中,
- 被当作,一个事件被注册,
- 一个回调函数被设置为在后台得到处理。
接下来是setTimeOut(...Two...),它也从回调栈中被添加到Node API,因为它是一个异步函数。然后另一个回调函数被设置为在后台超时2秒后被处理。直到这时,其他的功能可以被执行。
这就是所谓的非阻塞行为,所有的同步函数首先被处理和执行,而异步函数则在后台处理,同时等待轮到它们被执行。
接下来,console.log("End")函数在回调栈的最后被调用,并在这里得到处理。你可以看到终端上的输出。现在,所有的同步函数都被处理了,main()也从回调栈中被移除。
在后台,所有的异步函数被处理,它们的回调被存储在回调队列中。首先被处理的那个将被首先添加到回调栈的执行队列中。
注意:异步函数不能在回调栈内运行,直到它被清空。这意味着,在main()从调用堆栈中移除后,所有的异步函数才能开始执行。
现在,它们一个接一个地被推到使用事件循环的回调栈中,最后被执行。每个回调函数都将打印值,每次都会调用console.log()函数。
最后,这些在被执行后也被移除,现在回调栈是空的。
这就是NodeJS将如何在环境中执行同步和异步函数,以及事件循环如何管理调用异步函数。
总结
在这篇文章中,你了解了NodeJS的内部工作,看到了异步程序是如何被执行的。
现在你应该明白为什么两秒钟的延时函数不会阻止程序的其他部分执行。你也知道为什么零秒延时函数在 "End "打印后最后打印出数值了。
这就是全部! 我希望你喜欢阅读这篇文章,并学到一些新东西。如果你觉得这篇文章有用,请分享它(YES✌)。
复习一下
nodejs是如何处理同步和异步的?
- 通过事件来解决
- 遇到同步函数 - 放入回调栈(按栈的顺序执行)
- 遇到异步函数
- 先放入回调栈(不执行)
- 再从回调栈(同步)中,放入Node APIs,将该函数处理为一个事件,然后按照处理顺序(时间等)放入回调队列(异步)中
- 等回调栈都执行完(main函数也删除了),开始按回调队列中的顺序,放入回调栈中执行!
主要术语:事件、回调栈、回调队列、Node APIs
他年我若为青帝,报与桃花一处开。——黄巢《题菊花》