只在此山中,雲深不知處


聽首歌



© 2018 by Shawn Huang
Last Updated: 2018.5.27

Modules

Modules就是類似函式庫,我們可以將其導入然後使用,可以直接使用內建提供之函式庫,也可以自行建立,使用時使用關鍵字require()函數來引入。將部分程式碼寫入另一個檔案可以讓我們的主要程式碼不會過於冗長,而且便於管理與偵錯,並且可以重複使用。

自訂module


自訂module的方式就是先寫好要使用的函數於另一個檔案中,之後再使用關鍵字require導入即可,首先開啟一個module2_1.js的檔案,在其中建立以下函數:
注意要使用exports關鍵字來輸出函數,將此檔案儲存於同一個資料夾(Node_Demo)。也可以寫成以下形式,原則上是相同的。若是private函數或是任何不需要export的函數,只要不要加上exports即可,沒有被exports的函數在主程式便無法使用。

事實上整個exports是一個物件,所以也可以使用以下方式,只要將函數一個一個寫進去物件即可,甚至可以加上參數(e.g. moduleName)。
接下來建立主要的nodejs檔案(e.g. node2_1.js),在其中使用以下程式碼: 可看到第一行使用require函數導入module2_1這個module,請注意之前須有./,表示是在同一個資料夾內的module。導入後指派給變數myModule,因為沒有要改變,可以使用const,也可以使用var(or let)。第二行與第三行便是直接呼叫myModule內的函數即可。一樣在DOS介面內輸入node node2_1.js,可以看到輸出結果。
在剛剛的module裡,加上下列程式碼: 第一個Warrior是一個物件,第二個Mage則傳回一個物件,在主程式中輸入以下程式碼: 結果顯示tom跟aaron的結果相同,顯然兩者共享同一個物件,而mary與helen則不相同,兩者為獨立的物件,我們可以藉由如此方式來分享或建立物件。

Core modules (Built in modules)


Core modules (或Built in modules)是node.js的內建函式庫,也就是我們安裝好node.js後可以直接使用的module,因為是內建的,所以直接使用require(moduleName)即可導入,不像自訂module還要考慮檔案路徑。以下介紹幾個例子,詳細列表可以參考官網

path & url


>>

這個例子使用path module,直接使用require()函數導入。normalize()函數可以幫我們正常化路徑,在不同的作業系統,路徑的表示可能有不同,有的時候是斜線(\)有的時候是反斜線(/),這個函數可以轉化為目前系統的型態。dirname(), basename(), extname()這三個函數分別傳回C:\Course\Nodejs, node1.js, 與.js,看結果應該就知道指路徑的哪個部位。
parse()這個函數可以將路徑轉換為物件,其中包含dir, root, base, name, ext等變數,看輸出即可知其意義。其他path方法可以參考官網
>>
這個例子使用url module,一樣使用require()函數導入即可,使用parse()函數將其轉為物件,根據輸出可以看出host, hostname, pathname, search等參數所代表的意義。

os


os是跟作業系統相關的函數集,使用方式與前同。
>>

使用os函數可以得到跟operating system有關的資訊。

file system(fs)


fs顯然跟檔案系統有關,直接看以下例子:
>>
導入fs之後,使用writeFileSync()函數將txt寫到temptxt.txt檔案內,再使用appendFileSync()函數增加內容,之後使用readFileSync()函數讀出檔案內容並印出。注意讀出後要使用toString()函數,否則會出現一堆二進位數值內容。
>>
加上這些程式碼後,期待跟上列的程式碼出現一樣的結果,不過事實上這段程式碼的輸出卻可能沒有照著順序出現。原因是這些函數是Asynchronous,而之前的函數是Syncrhonous(Sync)。Syncrhonous(同步)的意思是當我們呼叫該函數,該函數完成後,才會去進行其他步驟。而Asynchronous(異步)的函數被呼叫後,不需等待該步驟完成,便可以去進行其他步驟。通常Asynchronous的函數會被賦予一個參數為callback函數,當函數完成要求後,接著會執行callback函數,在函數要求尚未被滿足前,程式可能先去執行其他部分的程式碼,等到偵測到函數要求被滿足後,接下來才要執行callback函數的程式碼。通常這個callback函數的第一個參數為err(Error)。至於應該要使用哪一種函數來實現我們的目的似乎見仁見智,如果是小檔案,不需要霸占整個流程,使用Asynchronous,若是不擔心霸占整個流程,可以使用Syncrhonous。
若要照步驟完成,可以將下一步寫進前一步的callback內。
>>

若要取得文件的統計資料,可以使用fs.stat()方法傳回fs.Stats物件。
>>

若要改檔案名,使用rename()。
>>
一樣一個是Syncrhonous,另一個是Asynchronous。
而若要刪除檔案,則使用unlink()。
>>
也是一樣一個是Syncrhonous,另一個是Asynchronous。
WriteStream & ReadStream --> see Events&Stream

Global Objects


Global Objects是在所有module內都可以被取得的物件,例如console。以下介紹幾個常見的例子。
>>
__dirname與__filename分別會得到目前目錄與檔案名稱。
>>
setTimeout()這個函數的語法是setTimeout(callback, delay[, ...args]),第一個參數callback是要做的事情,第二個參數delay是延遲時間,單位是毫秒,所以3000是3秒的意思。執行上述程式碼後會經過3秒才見到輸出。
>>
setInterval(callback, delay[, ...args])這個函數是每經過delay時間後便會重複執行callback函數。
>>
重寫上面setTimeout的code,使用clearTimeout()函數將會中止setTimeout函數。
>>
再重寫上面setInterval的code,使用clearInterval()函數將會中止setTimeout函數。

現在試一下以下的例子:
>>
若是將setTimeout()的delay改為0秒,可以發現setTimeout()內的內容還是最後才被執行。因為asynchronous的callback會先被安排至一個task queue,等其他程式碼被執行後,才會依序執行task queue內的事件,所以會在之後執行。