Home  >  Article  >  Web Front-end  >  The story between node.js and macOS

The story between node.js and macOS

小云云
小云云Original
2017-12-18 11:22:141347browse

This article uses a short story to share with you the story between node.js and macOS. I hope it can help everyone.

George G did a small test on his computer, but the results were quite different than expected.

So let’s first take a look at what is written in this small test:

There are three files in total, and the total code does not exceed 15 lines

<span style="font-size: 14px;">parent.js</span>

<span style="font-size: 14px;">class Parent {}<br><br>module.exports = Parent<br></span>

<span style="font-size: 14px;">son.js</span>

<span style="font-size: 14px;">//加载时把模块文件名首字母大写了(不正确的)<br/>const Parent = require(&#39;./Parent&#39;)<br/><br/>class Son extends Parent {}<br/><br/>module.exports = Son<br/></span>

<span style="font-size: 14px;">test.js</span>

<span style="font-size: 14px;">//加载时把模块名首字母大写(不正确的)<br/>const ParentIncorrect = require(&#39;./Parent&#39;)<br/>//通过正确的模块文件名加载(正确)<br/>const Parent = require(&#39;./parent&#39;)<br/><br/>const Son = require(&#39;./son&#39;)<br/><br/>const ss = new Son()<br/><br/>//测试结果<br/>console.log(ss instanceof Parent) // false<br/>console.log(ss instanceof ParentIncorrect) // true<br/></span>

Classmate George G has the following questions:

  1. ##son.js<span style="font-size: 14px;"></span># Both ## and test.js<span style="font-size: 14px;"></span> have incorrect file name references (case issues). Why is no error reported?

  2. Test result, why

    ss instanceof ParentIncorrect === true<span style="font-size: 14px;"></span>? I tolerated not reporting an error, but why did I still think that I was the instance of the module that was loaded with an incorrect name?

#If you, classmate, already have a clear understanding of the above issues, congratulations, Wen Neng can write a pen to calm the sky, and Wu Neng can mount a horse to determine the world; go to the kang to know your mother. Let’s get down on the kang and learn about shoes!

But if you don’t know why? Okay then, some of me will say it, and some of you will see it.

In fact, the method of diagnosis (debugging) is similar to that of traditional Chinese medicine. You can choose one or two of the four methods of looking, smelling, asking, and palpating to find the answer. .

Hope

There is not much code. After reading it for a while, even without my comments, I believe that careful students will find the real file. If there is a discrepancy between the name and the code when it is introduced, then there must be a problem here. Remember the problem, let’s continue

hear

Even if , I can’t smell anything in the code

Ask

Come on, a very important part of software engineering is Communication may not necessarily be with colleagues who encounter bugs. It may be yourself, it may be QA, and of course it may be PM or your boss. You didn't ask the question you wanted to know; he didn't make it clear what he wanted to answer; it's all over. . . .

So what do I want to know? The following two things are more reasonable as the entrance to debugging:

  1. operating system

  2. Run Environment + Version

  3. How did you test, command line or other means

Answer: macOS;

node.js > 8.0<span style="font-size: 14px;"></span>; Command linenode test.js<span style="font-size: 14px;"> </span>

chet

The exciting and profound moment has arrived, and I’m going to take action. (In order to fully describe the

debug<span style="font-size: 14px;"></span> process, I will pretend that I don’t know everything below in advance)

Prepare the computer, completed

Prepare the running environment

node.js > 9.3.0<span style="font-size: 14px;"></span>, Completed

Copied the code, completed

Run it, it was amazing, no error was reported, and the running result was what George G said.

In order to prove that I am not blind, I tried again

in <span style="font-size: 14px;">test.js</span><span style="font-size: 14px;"> </span>require<span style="font-size: 14px;"></span> A file that does not exist at allrequire('./nidayede')<span style="font-size: 14px;"></span>, run the code.

Fortunately, an error was reported this time

Error: Cannot find module './nidayede'<span style="font-size: 14px;"></span>, so I didn’t Crazy. That's a real joy.

So there is the first question

Why can Gouri’s module name still be loaded despite the wrong case?

Is it related to the operating system? Let's try again on <span style="font-size: 14px;">windows</span>. Sure enough, we got to <span style="font-size: 14px;">windows</span> , the case issue is a problem, <span style="font-size: 14px;">Error: Cannot find module './Parent'</span> .

So what is <span style="font-size: 14px;">macOS</span> doing? Can't you tell the difference between uppercase and lowercase? So hurry up<span style="font-size: 14px;">google</span> (Don’t ask me why not baidu)

The story between node.js and macOS

It turns out that the awesome <span style="font-size: 14px;">OS X</span> uses the <span style="font-size: 14px;">case-insensitive</span> file by default. system (detailed documentation).

but why? What is the purpose of such an anti-human design?

The story between node.js and macOS

More explanations, come and go

So, this is the reason why you don’t report an error ? (blaming <span style="font-size: 14px;">node.js</span>) But that’s the whole truth.

But the matter is not over yet

So what the hell is it like to have a thief as your father?

I have vaguely heard of it. Is there any cache in <span style="font-size: 14px;">node.js</span>? Is it caused by that thing? So in the mood to give it a try, I put <span style="font-size: 14px;">const ParentIncorrect = require('./Parent')</span> and <span style="font-size: 14px;">const Parent = require('./parent')</span> I changed the position and thought, would it be right to load it with the correct name first?

Sure enough, is still wrong. You can't really solve the problem by guessing and pretending

NaBibi<span style="font-size: 14px;">ParentIncorrect</span> and## Where is #Parent<span style="font-size: 14px;"></span>? So I wrote console.log(ParentIncorrect === Parent)<span style="font-size: 14px;"></span>, and the result was false<span style="font-size: 14px;"></span>. So they are really not the same thing, so the problem may be in the introduction part?

So the idea of ​​pretending to look at the source code of node.js<span style="font-size: 14px;"></span> was born (in fact, if you don’t look at it, the problem is ultimately I can also figure it out). After a long day, with a feeling of trepidation, I finally clone<span style="font-size: 14px;"></span>node.js<span style="font-size: 14px;"></span> Source code (it took a long time, so slow)

Come, let’s enter the mysterious node.js<span style="font-size: 14px;"></span> Source code world. Since our question is about require<span style="font-size: 14px;"></span>, let's start with her, but find require<span style="font-size: 14px;"></span> The definition process requires some patience. I won’t go into details here. I’ll just talk about the search sequence.

##src/node_main.cc => src/node. cc => lib/internal/bootstrap_node.js => lib/module.js<span style="font-size: 14px;"> </span>

Found it, this is it

lib/ module.js<span style="font-size: 14px;"></span>, get to the point:

lib/module.js => require

<span style="font-size: 14px;">Module.prototype.require = function(path) {<br/>  assert(path, &#39;missing path&#39;);<br/>  assert(typeof path === &#39;string&#39;, &#39;path must be a string&#39;);<br/>  return Module._load(path, this, /* isMain */ false);<br/>};<br/></span>

好像没什么卵用,对不对?她就调用了另一个方法 <span style="font-size: 14px;">_load</span> ,永不放弃,继续

lib/module.js => _load

<span style="font-size: 14px;">Module._load = function(request, parent, isMain) {<br/>  //debug代码,么卵用,跳过<br/>  if (parent) {<br/>    debug(&#39;Module._load REQUEST %s parent: %s&#39;, request, parent.id);<br/>  }<br/><br/>  if (isMain && experimentalModules) {<br/>    //...<br/>    //...<br/>    //这段是给ES module用的,不看了啊<br/>  }<br/><br/>  //获取模块的完整路径<br/>  var filename = Module._resolveFilename(request, parent, isMain);<br/><br/>  //缓存在这里啊?好激动有没有?!?终于见到她老人家了<br/>  //原来这是这样的,简单的一批,毫无神秘感啊有木有<br/>  var cachedModule = Module._cache[filename];<br/>  if (cachedModule) {<br/>    updateChildren(parent, cachedModule, true);<br/>    return cachedModule.exports;<br/>  }<br/><br/>  //加载native但非内部module的,不看<br/>  if (NativeModule.nonInternalExists(filename)) {<br/>    debug(&#39;load native module %s&#39;, request);<br/>    return NativeModule.require(filename);<br/>  }<br/><br/>  //构造全新Module实例了<br/>  var module = new Module(filename, parent);<br/><br/>  if (isMain) {<br/>    process.mainModule = module;<br/>    module.id = &#39;.&#39;;<br/>  }<br/><br/>  //先把实例引用加缓存里<br/>  Module._cache[filename] = module;<br/><br/>  //尝试加载模块了<br/>  tryModuleLoad(module, filename);<br/><br/>  return module.exports;<br/>};<br/></span>

似乎到这里差不多了,不过我们再深入看看 <span style="font-size: 14px;">tryModuleLoad</span>

lib/module.js => tryModuleLoad

<span style="font-size: 14px;">function tryModuleLoad(module, filename) {<br/>  var threw = true;<br/>  try {<br/>    //加载模块<br/>    module.load(filename);<br/>    threw = false;<br/>  } finally {<br/>    //要是加载失败,从缓存里删除<br/>    if (threw) {<br/>      delete Module._cache[filename];<br/>    }<br/>  }<br/>}<br/></span>

接下来就是真正的 <span style="font-size: 14px;">load</span> 了,要不我们先停一停?

好了,分析问题的关键在于不忘初心,虽然到目前为止我们前进的比较顺利,也很爽对不对?。但我们的此行的目的并不是爽,好像是有个什么疑惑哦!于是,我们再次梳理下问题:

  1. <span style="font-size: 14px;">son.js</span> 里用首字母大写(不正确)的模块名引用了 <span style="font-size: 14px;">parent.js</span>

  2. <span style="font-size: 14px;">test.js</span> 里,引用了两次 <span style="font-size: 14px;">parent.js</span> ,一次用完全一致的模块名;一次用首字母大写的模块名。结果发现 <span style="font-size: 14px;">son instanceof require('./parent') === false</span>

既然没报错的问题前面已经解决了,那么,现在看起来就是加载模块这个部分可能出问题了,那么问题到底是什么?我们怎么验证呢?

这个时候我看到了这么一句话 <span style="font-size: 14px;">var cachedModule = Module._cache[filename];</span> ,文件名是作为缓存的 <span style="font-size: 14px;">key</span> ,来吧,是时候看看 <span style="font-size: 14px;">Module._cache</span> 里存的模块 <span style="font-size: 14px;">key</span> 都是什么牛鬼蛇神了,打出来看看吧,于是我在 <span style="font-size: 14px;">test.js</span> 里最后面加了一句 <span style="font-size: 14px;">console.log(Object.keys(require.cache))</span> ,我们看看打出了什么结果

<span style="font-size: 14px;">false<br/>true<br/>[ &#39;/Users/admin/codes/test/index.js&#39;,<br/>  &#39;/Users/admin/codes/test/Parent.js&#39;,<br/>  &#39;/Users/admin/codes/test/parent.js&#39;,<br/>  &#39;/Users/admin/codes/test/son.js&#39; ]<br/></span>

真相已经呼之欲出了, <span style="font-size: 14px;">Module._cache</span> 里真的出现了两个 <span style="font-size: 14px;">[p|P]arent</span><span style="font-size: 14px;">macOS</span> 默认不区分大小写,所以她找到的其实是同一个文件;但 <span style="font-size: 14px;">node.js</span> 当真了,一看文件名不一样,就当成不同模块了),所以最后问题的关键就在于 <span style="font-size: 14px;">son.js</span> 里到底引用时用了哪个名字(上面我们用了首字母大写的 <span style="font-size: 14px;">require('./Parent.js')</span> ),这才导致了 <span style="font-size: 14px;">test.js</span> 认贼作父的梗。

如果我们改改 <span style="font-size: 14px;">son.js</span> ,把引用换成 <span style="font-size: 14px;">require('./parEND.js')</span> ,再次执行下 <span style="font-size: 14px;">test.js</span> 看看结果如何呢?

<span style="font-size: 14px;">false<br/>false<br/>[ &#39;/Users/haozuo/codes/test/index.js&#39;,<br/>  &#39;/Users/haozuo/codes/test/Parent.js&#39;,<br/>  &#39;/Users/haozuo/codes/test/parent.js&#39;,<br/>  &#39;/Users/haozuo/codes/test/son.js&#39;,<br/>  &#39;/Users/haozuo/codes/test/parENT.js&#39; ]<br/></span>

没有认贼作父了对不对?再看 <span style="font-size: 14px;">Module._cache</span> 里,原来是 <span style="font-size: 14px;">parENT.js</span> 也被当成一个单独的模块了。

So, assuming your module file name has <span style="font-size: 14px;">n</span> characters, theoretically, in <span style="font-size: 14px;"> macOS</span> In a case-insensitive file system, you can <span style="font-size: 14px;">node.js</span> maximize it<span style="font-size: 14px;">2</span> of <span style="font-size: 14px;">n</span> power caches to

Isn’t it miserable! ? Fortunately <span style="font-size: 14px;">macOS</span> You can still change it to case-sensitive, reinstall the system from a grid disk, or create a new partition.

Although the problem is not difficult, the determination and ideas to explore the problem are still important.

Related recommendations:

Teach you how to use node.js to create a child process

PHP and Node.js

node.js publish-subscribe mode method

The above is the detailed content of The story between node.js and macOS. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn