当前位置: 首页 > 后端技术 > Node.js

[翻译]你不知道的Node

时间:2023-04-03 11:55:04 Node.js

你不知道的Node原文:你不知道的Node译者:neal1991欢迎star我的文章翻译器,为您提供文章进阶翻译。任何建议,请发布或联系我LICENSE:在今年麻省理工学院的Forward.js(一种JavaScript)会议上,我发表了题为“你不知道节点”的演讲。在本次演讲中,我向观众提出了一些关于Node.js运行时的挑战性问题,其中大多数技术相关性最高的观众无法回答。我没有做实际的统计数据,但这就是那个房间里的感觉。演讲结束后,听众中一些勇敢的人向我承认了这一事实。这就是为什么我要发表这个演讲。我认为我们没有以正确的方式教授Node!大多数与Nodejs相关的教学概念都集中在Node包上,而不是它的运行时。大多数包将Node运行时包装在模块中(例如http或stream)。当你遇到问题时,这些问题可能存在于运行时,如果你不知道Node正在运行,你就有麻烦了。问题:大多数与Nodejs相关的教学概念都集中在Node包而不是它的运行时我为本文选择了一些问题并进行了回答。它们将在下面作为标题呈现。尝试先在自己的脑海中回答!如果您发现错误或误导性答案,请告诉我。问题#1:什么是调用堆栈,它是V8的一部分吗?调用堆栈当然是V8的一部分。它是V8用来跟踪函数调用的一种数据结构。每次我们调用一个函数时,V8都会将对该函数的引用压入函数调用栈,对于其他函数的嵌套函数也会这样做。这也包括递归调用函数的函数。当函数中的嵌套函数到达末尾时,V8一次弹出一个函数,并在其位置使用返回值。为什么了解Node很重要?因为每个Node进程只能获得一个调用栈。如果你让这个调用栈一直很忙,你的整个Node进程也会很忙。记住这一点。问题#2:什么是事件循环?它是V8的一部分吗?你认为事件循环在这张图中的什么位置?事件循环由libbuv库提供,它不是V8的一部分。事件循环处理外部事件并将它们转换为回调调用。这是一个从事件队列中取出事件并将其回调推送到调用堆栈的循环。它也是一个多相回调。如果这是您第一次听说事件循环,这些概念可能不会那么有用。此事件循环是更大图片的一部分。您需要了解这张更大的图片才能理解事件循环。您需要了解V8的作用,了解NodeAPI,并了解事件如何排队等待V8执行。Node的API只是像setTimeout或fs.readFile这样的函数。这些不是JavaScript的一部分。它们是Node.js提供的函数。事件循环位于该图的中间(实际上是一个更复杂的版本),就好像它是一个组织者一样。当V8调用栈为空时,事件循环可以决定接下来执行哪一个。问题#3:当调用堆栈和事件循环为空时,Node会做什么?很简单,它将退出。当你运行一个Node程序时,Node会自动启动事件循环,当事件循环变得空闲并且没有其他事可做时,进程就会退出。为了保持Node运行,你需要在某个地方的事件队列中放置一些东西。例如,当您启动计时器或HTTP服务时,您基本上告诉事件循环继续运行并检查这些事件。问题#4:除了V8和Libuv,Node还有哪些外部依赖?以下是Node需要的所有单独的库:http-parserc-aresOpenSSLzlib都是Node的外部依赖。他们有自己的源代码。他们有自己的证书。节点只是使用它们。你想记住是因为你想知道你的程序在哪里运行。如果您正在处理数据压缩,您可能会在使用某些zlib库时遇到一些困难。您可能正在解决zlib错误。不要把一切都归咎于Node。问题#5:是否可以在没有V8的情况下运行Node?这可能是一个棘手的问题。您需要一个VM来运行Node进程,但V8并不是您可以尝试的唯一VM。你可以使用脉轮。获取Github存储库以跟踪node-chakra的进度:https://github.com/nodejs/nod...问题#6:module.exports和exports之间有什么区别?你总是可以尝试module.exports来导出你的模块的API。除了一种情况,您还可以导出:module.exports.g=...//Okexports.g=...//Okmodule.exports=...//Okexports=...//不行,为什么?exports只是module.exports的引用或别名。当您更改导出时,您正在更改该引用而不是更改官方API(module.exports)。您只会获得模块范围内的局部变量。问题#7:为什么顶级变量不是全局的?如果你有一个module1定义了一个顶级变量g://module1.jsvarg=42;而你有一个module2导入了module1并尝试访问变量g,你会发现g是未定义的。为什么?如果你在浏览器中做同样的事情,你可以在所有变量定义后导入后访问顶级变量。每个Node文件在幕后都有自己的立即调用函数表达式(IIFE)。这个Node文件中定义的所有变量都在这个IIFE的范围内。相关问题:运行以下仅包含一行代码的节点文件的输出是什么://script.jsconsole.log(arguments);你会看到一些争论!为什么?因为Node执行一个函数。Node将您的代码包装在一个函数中,该函数准确定义了您在上面看到的5个参数。问题#8:对象exports、require和module在每个文件中都是全局可用的,但每个文件都不同。这怎么可能?当你需要使用require对象时,你可以直接使用它,就像它是一个全局变量一样。但是,如果您在两个不同的文件中检查require,您将看到两个不同的对象。这怎么可能?都是因为同一个神奇的IIFE:如您所见,神奇的IIFE将您的代码传递给5个参数:exports、require、modue、__filename和__dirname。当你在Node中尝试这5个参数时,它们看起来是全局的,但实际上它们只是函数参数。问题#9:什么是Node中的循环模块依赖?如果您有一个导入模块2的模块1,而同一个模块2导入模块1,会发生什么情况?一个失误?//module1require('./module2');//module2require('./module1');你不会得到一个错误。节点允许这样做。那么当module1导入module2时,但是由于module2需要module1,而module1还没有完成,module1只会得到module2的部分版本。你会被警告。问题#10:什么时候可以在文件系统中尝试同步方法(例如readFileSync)?Node中的每个fs方法都有一个同步版本。为什么要使用同步方法而不是异步方法?有时使用同步方法很好。例如,在服务器仍在加载时在初始化步骤中使用同步方法。在大多数情况下,初始化步骤之后的一切都取决于初始化步骤中获得的数据。在不引入回调的级别,使用同步方法是可以接受的,只要您对同步方法的使用是一次性的。但是,如果您在处理程序中尝试同步方法,例如HTTP服务器请求回调,显然100%的时间都会失败。不要那样做。我希望您能回答部分或所有这些具有挑战性的问题。除了Node.js的基本概念之外,我还会给出一些文章。https://medium.freecodecamp.o...https://medium.freecodecamp.o...https://medium.freecodecamp.o...https://medium.freecodecamp.o...https://medium.freecodecamp.o...https://medium.freecodecamp.o...