搜尋
首頁web前端js教程關於node.js和macOS之間的故事

關於node.js和macOS之間的故事

Dec 18, 2017 am 11:22 AM
javascriptmacosnode.js

本文由一個小故事來和大家分享關於node.js和macOS之間的故事,希望能幫助大家。

喬治G在他的電腦上做了一個小測試,但結果和預期的大不相同。

那麼我們先來看看這個小測試都寫了什麼:

總共三個文件,程式碼總計不超過15行

<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>

喬治G同學有以下問題:

  1. <span style="font-size: 14px;">son.js</span><span style="font-size: 14px;">test.js</span> 裡都有錯誤的檔名(大小寫問題)引用,為什麼不報錯?

  2. 測試結果,為什麼 <span style="font-size: 14px;">ss instanceof ParentIncorrect === true</span> ?不報錯我忍了,為什麼還認賊作父,說自己是那個透過不正確名字載入出來的模組的instance?

如果同學你對上述問題已經了然於胸,恭喜你,文能提筆安天,武能上馬定乾坤;上炕認識娘們,下炕認識鞋!

但如果你也不是很清楚為什麼?那麼好了,我有的說,你有的看。

其實斷症(裝逼範兒的debug)之法和中醫看病也有相似指出,望、聞、問、切四招可以按需選取一二來尋求答案。

程式碼不多,看了一會兒,即使沒有我的註釋,相信仔細的同學也都發現真正的文件名和程式碼中引入時有出入的,那麼這裡肯定是有問題的,問題記住,我們繼續

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

#這個就算了,程式碼我也聞不出個什麼鬼來

#來吧,軟體工程裡很重要的一環,就是溝通,不見得是和遇到bug的同事,可能是自己,可能是QA,當然也可能是PM或是你的老闆。你沒問出自己想知道的問題;他沒說清楚自己要回答的;都完蛋。 。 。 。

那我想知道什麼呢?以下兩件事作為debug的入口比較合理:

  1. 作業系統

  2. ##運行環境+ 版本<span style="font-size: 14px;"></span>

  3. 你怎麼測試的,命令列還是其他什麼手段<span style="font-size: 14px;"></span>

答曰:macOS; <span style="font-size: 14px;"></span>node.js > 8.0<span style="font-size: 14px;"></span># ;命令列<span style="font-size: 14px;"></span>##node test.js<span style="font-size: 14px;"> </span>

#切

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

令人興奮的深刻到來了,我要動手了。 (為了完整的描述

<span style="font-size: 14px;"></span>debug<span style="font-size: 14px;"></span> 過程,我會假裝這下面的所有事情我事先都是不知道的)<span style="font-size: 14px;"></span>

準備電腦,完成

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

準備運行環境

<span style="font-size: 14px;"></span>#node.js > 9.3.0<span style="font-size: 14px;">## ,完畢</span><span style="font-size: 14px;"></span>復刻程式碼,完畢

<span style="font-size: 14px;"></span>#運行,日了狗,果然沒報錯,而且運行結果就是喬治G說的那樣。

<span style="font-size: 14px;"></span>為了證明我沒瞎,我又嘗試在

​​

#test.js<span style="font-size: 14px;"> 裡</span><span style="font-size: 14px;"></span><span style="font-size: 14px;"></span><span style="font-size: 14px;"></span> <span style="font-size: 14px;">require</span> 了一個壓根不存在的檔案

#require('./nidayede')<span style="font-size: 14px;"></span> ,執行程式碼。 <span style="font-size: 14px;"></span>還好這次報錯了

Error: Cannot find module './nidayede'<span style="font-size: 14px;"></span>

,所以我沒瘋。這點真令人高興。 ############於是有了第一個問題#######

為什麼狗日的模組名稱大小寫都錯了,還能載入?

會不會跟作業系統有關係?來我們再找台<span style="font-size: 14px;">windows</span> 試試,果然,到了<span style="font-size: 14px;">windows</span>## 上,大小寫問題就是個問題了, <span style="font-size: 14px;"></span>Error: Cannot find module './Parent'<span style="font-size: 14px;"></span> 。 <span style="font-size: 14px;"></span>

那麼 <span style="font-size: 14px;"></span>macOS<span style="font-size: 14px;"></span># 到底在做什麼?連個大小寫都分不出來麼?於是趕緊<span style="font-size: 14px;"></span>google<span style="font-size: 14px;"></span>(別問我為什麼不baidu)<span style="font-size: 14px;"></span>

關於node.js和macOS之間的故事

##原來人家牛逼的

OS X<span style="font-size: 14px;"></span> 預設用了<span style="font-size: 14px;"></span>case-insensitive<span style="font-size: 14px;"></span> 的文件系統( 詳細文件)。 <span style="font-size: 14px;"></span>

but why?這麼反人類的設計到底是為了什麼?

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

關於node.js和macOS之間的故事

更多解釋, 來,走你

所以,這就是你不報錯的理由? (對

<span style="font-size: 14px;"></span>node.js<span style="font-size: 14px;"></span> 指責道),但這就是全部真相了。 <span style="font-size: 14px;"></span>

但事情沒完

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

那認賊作父又是個什麼鬼?

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

依稀有聽過

<span style="font-size: 14px;"></span>node.js<span style="font-size: 14px;"></span> 裡面有什麼緩存,是那個東西引起的麼?於是抱著試試看的心情,我把<span style="font-size: 14px;"></span>const ParentIncorrect = require('./Parent')<span style="font-size: 14px;"></span> 和<span style="font-size: 14px;"></span>const Parent = require('./parent')<span style="font-size: 14px;"></span> 換了下位置,心想,這樣最先按照正確的名字加載,會不會就對了呢? <span style="font-size: 14px;"></span>

果然,

還是不對 。靠猜和裝逼是不能夠真正解決問題的

那比比

<span style="font-size: 14px;"></span>ParentIncorrect<span style="font-size: 14px;"></span> 和<span style="font-size: 14px;"></span><span style="font-size: 14px;"></span><span style="font-size: 14px;"></span><span style="font-size: 14px;"></span><span style="font-size: 14px;"></span><span style="font-size: 14px;"></span><span style="font-size: 14px;"></span>

<span style="font-size: 14px;"></span><span style="font-size: 14px;"></span>Parent<span style="font-size: 14px;"></span> 呢?於是我寫了<span style="font-size: 14px;"></span>console.log(ParentIncorrect === Parent)<span style="font-size: 14px;"></span> ,結果是<span style="font-size: 14px;"></span>false<span style="font-size: 14px;"></span> 。所以他兩個真的不是同一個東西,那麼說明問題可能在引入的部分嘍?

<span style="font-size: 14px;"></span>於是一個裝逼看<span style="font-size: 14px;"></span>node.js<span style="font-size: 14px;"></span> 原始碼的想法誕生了(其實不看,問題最終也能想明白)。 日了狗,懷著忐忑的心情,終於<span style="font-size: 14px;"></span>clone<span style="font-size: 14px;"></span># 了一把<span style="font-size: 14px;">##node.js</span> # 原始碼(花了好久,真tm慢)

來,我們一起進入神秘的<span style="font-size: 14px;"></span>node.js

原始碼世界。既然我們的問題是有關<span style="font-size: 14px;">require</span> 的,那就從她開始吧,不過找到

##require

<span style="font-size: 14px;"></span> 定義的過程需要點耐心,這裡不詳述,只說查找的順序吧

############src/node_main.cc => src/node. cc => lib/internal/bootstrap_node.js => lib/module.js###### ########找到咯,就是這個##########lib/ module.js######### ,進入正題:#############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> 也被当成一个单独的模块了。

所以,假設你的模組檔名有<span style="font-size: 14px;">n</span># 字符,理論上,在<span style="font-size: 14px;"># macOS</span> 大小寫不敏感的檔案系統裡,你能讓<span style="font-size: 14px;">#node.js</span> 將其弄出最大<span style="font-size: 14px;">2</span><span style="font-size: 14px;">n</span> 次方個快取來

#是不是很慘! ?還好 <span style="font-size: 14px;">macOS</span> 還是可以改成大小寫敏感的,格盤重裝系統;新分割區都行。

問題雖然不難,但探究問題的決心和想法還是重要的。

相關推薦:

教大家如何利用node.js建立子程式

#PHP與Node.js

#node.js 發布訂閱模式的方法

以上是關於node.js和macOS之間的故事的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
JavaScript是用C編寫的嗎?檢查證據JavaScript是用C編寫的嗎?檢查證據Apr 25, 2025 am 12:15 AM

是的,JavaScript的引擎核心是用C語言編寫的。 1)C語言提供了高效性能和底層控制,適合JavaScript引擎的開發。 2)以V8引擎為例,其核心用C 編寫,結合了C的效率和麵向對象特性。 3)JavaScript引擎的工作原理包括解析、編譯和執行,C語言在這些過程中發揮關鍵作用。

JavaScript的角色:使網絡交互和動態JavaScript的角色:使網絡交互和動態Apr 24, 2025 am 12:12 AM

JavaScript是現代網站的核心,因為它增強了網頁的交互性和動態性。 1)它允許在不刷新頁面的情況下改變內容,2)通過DOMAPI操作網頁,3)支持複雜的交互效果如動畫和拖放,4)優化性能和最佳實踐提高用戶體驗。

C和JavaScript:連接解釋C和JavaScript:連接解釋Apr 23, 2025 am 12:07 AM

C 和JavaScript通過WebAssembly實現互操作性。 1)C 代碼編譯成WebAssembly模塊,引入到JavaScript環境中,增強計算能力。 2)在遊戲開發中,C 處理物理引擎和圖形渲染,JavaScript負責遊戲邏輯和用戶界面。

從網站到應用程序:JavaScript的不同應用從網站到應用程序:JavaScript的不同應用Apr 22, 2025 am 12:02 AM

JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。

Python vs. JavaScript:比較用例和應用程序Python vs. JavaScript:比較用例和應用程序Apr 21, 2025 am 12:01 AM

Python更適合數據科學和自動化,JavaScript更適合前端和全棧開發。 1.Python在數據科學和機器學習中表現出色,使用NumPy、Pandas等庫進行數據處理和建模。 2.Python在自動化和腳本編寫方面簡潔高效。 3.JavaScript在前端開發中不可或缺,用於構建動態網頁和單頁面應用。 4.JavaScript通過Node.js在後端開發中發揮作用,支持全棧開發。

C/C在JavaScript口譯員和編譯器中的作用C/C在JavaScript口譯員和編譯器中的作用Apr 20, 2025 am 12:01 AM

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。1)C 用于解析JavaScript源码并生成抽象语法树。2)C 负责生成和执行字节码。3)C 实现JIT编译器,在运行时优化和编译热点代码,显著提高JavaScript的执行效率。

JavaScript在行動中:現實世界中的示例和項目JavaScript在行動中:現實世界中的示例和項目Apr 19, 2025 am 12:13 AM

JavaScript在現實世界中的應用包括前端和後端開發。 1)通過構建TODO列表應用展示前端應用,涉及DOM操作和事件處理。 2)通過Node.js和Express構建RESTfulAPI展示後端應用。

JavaScript和Web:核心功能和用例JavaScript和Web:核心功能和用例Apr 18, 2025 am 12:19 AM

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具