2024/3/12 发布
正在寻觅一份前端开发工作,如果您觉得这篇文章对你有所帮助,这是我的简历1
在这篇文章中你能学习和理解:NodeJS是如何工作、如何处理所有发送给服务器的函数(无论同步或者异步)和请求、Event Loops in NodeJS 。就是在NodeJS环境中同步代码和异步代码是如何执行的,以及event loop是如何管理异步代码的。
背景
想必每位前端开发工程师都能在NodeJS官网-学习入门 处看到这样一句话:NodeJS is an asynchronous event-driven JavaScript runtime environment designed to build scalable network applications.
理解什么是Asynchronous(异步)?
这里的Asynchronous指的是 那些在后台(background)处理不堵塞(blocking)任何其他请求(request)的JS函数(function)
理解什么是Event Loop (事件循环)
在NodeJS 环境中,Node用Event Loop 处理请求。
An event loop是一个内置在NodeJS环境中的事件监听者,它所拥有的一些函数随时准备去监听,处理和为事件进行输出。
用英文解释会更清楚:An event loop is an event-listener which functions inside the NodeJS environment and is always ready to listen, process, and output for an event.
PS:一个事件(an event)可以是鼠标事件,定时事件,键盘事件等。
理解什么是Synchronous programming(同步程序) and Asynchronous programming?
同步程序就是the code运行遵循书写下的序列(sequence),在同步程序中只有一个函数被调用并返回了一个值之后,下一行的函数才能执行。
让我们用以下的代码举个例子:
const listItems = function(items) {items.forEach(function(item) {console.log(item)})
}const items = ["Buy milk", "Buy coffee"]listItems(items)
The output will look like this:
“Buy milk”
“Buy coffee”
在这个例子中,当listItems(items)
函数被调用后,它会循环抓取items数组元素,console.log(item)
函数得到数组第一个元素后输出"Buy milk".然后console.log(item)
再次执行时,通过数组第二个元素,输出"Buy coffee"
这就是所谓的函数遵循书写下的序列执行。
换句话来说,异步程序就是代码执行并不遵循明确的序列(sequence)。这些函数并不表现为一个程序中定义的序列,而仅仅当遇见确定的条件。
举个例子,setTimeOut() 表现为在提前指定的毫秒延迟过后执行一个任务。
setTimeOut(function(){return( console.log("Hello World!") )
}, 3000)
这类函数并不是根据书写顺序一行行得运行,仅仅当他们需要被执行,和函数的声明无关,在这个例子中,在所有同步函数(synchronous function)都已经执行完过后,这个输出函数将会在3秒之后自动执行,在同步函数被执行完之前,异步函数会在后台被处理。
理解NodeJS 如何在后台处理异步函数 ,以及如何先执行所有同步函数?所有的这些机制,可以用NodeJS event loop轻松解释。
How Does an Event Loop Work?
用一个diagram来看看NodeJS event loop 如何执行一个简单的同步程序:
左上角是一个即将被执行的Node file,左下角是一个程序输出端,以及你会拥有 Call stack, Node APIs and Callback queue. 所有这些组成了这个 NodeJS environment.
对于同步程序,只需要关注call stack ,这是这个例子下,NodeJS 环境唯一会产生工作的地方。(call stack 就是一个数据结构,用于在程序中锁定所有函数的执行)
当程序开始执行,首先call stack 注入一个匿名main()
函数,这个机制是NodeJS默认的。
接下来,变量a和b被创建,以及他们的和被存储在变量sum中。所有的取值都被存储在内存中。
现在,console.log()
是一个函数,它被调用以及push到call stack ,然后执行,你就会在输出端的屏幕中看到它的输出结果。
当函数执行完毕,就会从call stack 中被移除。接着,当程序没有剩下的东西被调用,main()
也会被移出call stack。以上就是同步程序执行的过程。
现在,来看在NodeJS中异步程序如何执行。异步程序就需要call stack 、Node APIs、callback queue 全部一起参与处理。
看下面这个例子:
和上面的一样,当程序开始执行,第一步是main()
被添加到call stack中。然后console.log("Start")
被调用和添加到stack栈。进过处理,输出就在输出端被看见,接着就会从call stack 中被移除。
现在下一句是setTimeOut(...Zero...)
,函数被调用和添加到call stack。
因为这是一个异步函数,它不会在call stack中被处理,它从call stack 添加到Node APIs ,在Node APIs中:事件被注册,回调函数(callback function)被设置并在后台进行处理。
接下来setTimeOut(...Two..)
同样的道理进入Node APIs,接着又一个callback function 被设置为在后台两秒之后处理。当这个时刻到来之前,其他函数都可以被执行。
这叫做非阻塞式行为:直到满足条件轮到他们执行之前,所有的同步函数首先在后台被处理和执行
接下来,console.log("End")
函数被最后调用,并在call stack中处理,输出端可以看到输出结果。现在,所有的同步方法都被处理了,然后main()
被移除call stack。
在后台,所有的异步函数被处理以及所有的回调函数被存储在callback queue,首先处理的一个将首先添加到队列中,以便在回调堆栈中执行。
Note: Asynchronous functions cannot run inside a callback stack until it gets emptied. That means that after main() is removed from call stack, only then can all asynchronous functions start executing.
现在他们被event loop一个个得推入call stack 并得到执行。
每次被调用时这些回调函数都会用console.log()
函数打印value。
最后,这些都会被在执行过后被移除,现在call stack 再次清空了。
这就是NodeJS环境下 如何执行同步异步函数,以及event loop 如何管理调用异步函数。
Conclusion
在这篇文章中,你理解了NodeJS的内部工作机制,以及明白了异步程序如何被执行。
现在你应该理解为什么2秒的延迟函数没有阻塞其他的程序执行,你也明白为什么0秒的延迟函数在“End”输出后打印其值。
以上就是全部,我希望你们享受这篇文章的内容并学到一些新东西,分享这篇文章如果你觉得它有用!感谢你们的点赞关注和岗位内推!找到工作我会告诉大家!
我的简历:点击获取,欢迎随时联系我
If you want to learn more about NodeJS and asynchronous programming, you can refer to this article ↩︎