閱讀254 返回首頁    go 阿裏雲 go 技術社區[雲棲]


這事要從node node.js說起

導讀:興許所有程序員都有命名困難症,在考慮變量、常量、方法、類、文件等命名時,總會千方百計嚐試一些語義化的方式去實現。

曾經有那麼一段時間,一些node初學的同學遇到了同樣的問題:Hello World 跑不動!

原文首發於個人博客:這事要從node node.js說起

1. 謎之 Hello World

問題的起源非常簡單,當我們在編寫一個入門程序時,就會迅速想起那句膾炙人口的語句:

console.log('Hello World');

於是乎,順手保存為node.js,緊接著嚐試以node node.js來運行該示例程序。毫無疑問,在cmd環境下,會遇到如下的報錯:

exec

(PS:實際上無論是Mac、Linux用戶,亦或是WIndows中使用Powershell或其他終端環境的同學都無法與此問題完美邂逅)

3. 初步分析

此時此刻,心中一陣失落,居然連入門的示例程序都無法運行,不禁一陣瞎想:是否該放棄node.js了?

言歸正傳,細心的同學會發現,報錯的源頭來自Windows Script Host,下簡稱WSH,我們不難查到它是 Windows 操作係統腳本語言程序(script,即:腳本)的運行環境。

3. 執行了什麼?

簡單分析一下node node.js這條命令,我們會很自然地認定為:執行node.exe程序,參數為node.js。

然而實際上,真正執行的程序卻變成WSH,前麵執行的命令node node.js並沒有任何跟調起WSH相關的邏輯,因此為何調起了WSH成為了解謎的關鍵。

順蔓摸瓜,由於WSH正好是執行腳本的服務,而js恰恰又是腳本的一種,不妨假設node.js這個腳本文件就是罪魁禍首。然後創建一個test.js的副本,嚐試執行它:

exec2

2.1 執行程序的路徑

根據試驗的結果不難猜出node node.js命令實際執行了node.js這個腳本文件,從而調起WSH服務,進而出現上圖的報錯。

順水推舟可確定node node.js等價於.\node.js node.js,即命令執行的文件完整的路徑為:E:\test\node.js

(PS:各位看官切莫介懷'\'作為路徑分隔符,畢竟在cmd下'/'擔任參數分隔符的要職)

2.2 補全程序的路徑

先講講通用的說法,無論是 * nix 、OS/2 、DOS 亦或是 windows,其terminal都可以通過一個特殊的環境變量PATH進行“補全”(關於環境變量的詳細內容本文不作介紹)。

接下來我們通過ping命令先做簡要說明:

2.2.1 定位程序的路徑

ping

很明顯,在任何一台正常的機器上,這條命令執行後都能得到期待的結果。此時我們可以看到該cmd進程下的PATH環境變量中包含C:\WINDOWS\system32,通過對PATH中的元素(文件夾路徑)即可將ping程序的路徑補全為:C:\WINDOWS\system32\ping。(在 * nix 係統下依然通用)

path

2.2.2 補全後綴名(僅windows、dos)

由於windows的可執行的概念和 * nix 略有不同,因此在windows平台下還需要對程序進行後綴名的補全。

其中在 * inx下,隻需保證文件的結構符合規範,並且擁有可執行權限,就可以執行;而在windows下,還需要考慮其後綴名及執行方式(實際上是一種打開方式的策略)。

E:\test>echo %PATHEXT%
.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.PY;.PYW;.CPL

最終我們補全的程序路徑為:C:\WINDOWS\system32\ping.exe

2.2.3 特別注意(僅windows、dos)

針對於cmd環境,當前目錄也會作為路徑補全的一部分,並且優先級最高。在當前目錄下,我們創建一個ping.bat的腳本,並填充以下內容:

@echo off
:: 輸出完整的路徑和文件名及後綴
echo %~dpnx0

執行結果如下圖,原來的ping.exe的動作明顯被覆蓋了。

current_path

2.2.4 小結

我們也額外地發現windows的默認可執行的後綴名包含.JS,由此可推斷最初的那條node node.js命令最終補全的程序路徑為:E:\test\node.js

3 打開方式?

從2.2.4的結論中能顯而易見的推導出命令執行的程序為node.js腳本文件,那麼它為什麼是通過WSH去執行的呢?

答案其實很明顯,有個通俗易懂的概念,叫做打開方式,而windows的打開方式由assocftype確定。

3.1 後綴名與打開方式

嚐試性的跑一跑assoc命令,發現其控製著後綴名與打開方式ftype的關係。

assoc | findstr .js

運行結果:

.js=JSFile
.json=VisualStudio.json.14.0
.jsonld=VisualStudio.jsonld.14.0
.jsx=VisualStudio.jsx.14.0
.jsxbin=JSXBINFile
.jsxinc=JSXINCFile

不難看出.js文件將會通過JSFile這個打開方式去執行。

3.2 打開方式與執行程序

類似的,我們也可以運行一下ftype命令,其定義了可執行程序以及調用的參數。

ftype | findstr "JS"

運行結果:

JSEFile=C:\Windows\System32\WScript.exe "%1" %*
JSFile=C:\Windows\System32\WScript.exe "%1" %*
JSXFile="C:\Program Files (x86)\Adobe\Adobe Utilities - CS6\ExtendScript Toolkit CS6\ExtendScript Toolkit.exe" -run "%1"

其中最關鍵的信息為JSFile=C:\Windows\System32\WScript.exe "%1" %*,含義是通過WScript.exe執行js腳本,並將原來的參數傳遞過去。

最終node node.js等價於E:\test\node.js node.js

3.3 怎麼破?

  • 發動想象力吧,別再叫node.js了~
  • 是時候切換到 * inx 或者升級到powershell了~
  • 如果不介意使用絕對路徑的話……

4. 擴展學習

操作係統層麵通過PATH等環境變量進行資源定位的思路實際上也被廣泛應用在各種場景下,下麵也舉兩個常見的栗子說明一下。

4.1 npm 包定位

CommonJS 規範中通過require去加載模塊時,通過路徑補全的策略(詳情推薦閱讀《深入淺出Node.js》),可以省略模塊的路徑,後綴名,甚至連/index也能自動補全。

4.2 webpack資源定位

嘿,resolve中的extensions、alias等思路是否也如出一轍呢?

5. 總結

全文原創·此文為隨走隨記,全文思維略帶感情請勿拍磚。

最後更新:2017-08-28 09:03:33

  上一篇:go  Work like alibaba線下沙龍第一期回顧整理(含演講幻燈片、內容簡介):持續更新中
  下一篇:go  SQL優化器原理 - Auto Hash Join