1. 程式人生 > >nodejs模組和方法

nodejs模組和方法

1,模組載入規範

        ES6之前已經出現了js模組載入的方案,最主要的是CommonJS和AMD規範。commonjs主要應用於伺服器,實現同步載入,如nodejs。AMD規範應用於瀏覽器,如requirejs,為非同步載入。同時還有CMD規範,為同步載入方案如seaJS。

        Nodejs 有一個簡單的模組載入系統。在 Nodejs 中,檔案和模組是一一對應的(每個檔案被視為一個獨立的模組)。

        require方能看到的只有module.exports這個物件,它是看不到exports物件的,而我們在編寫模組時用到的exports物件實際上只是對module.exports的引用。

 

2,module.exports和exports

        Nodejs 中的每一個模組都會自動建立一個 module 物件,同時 module 物件下有一個叫 exports 的屬性,可以將某個類的例項賦值給 module.exports,從而匯出這個類的例項。

        在模組被執行前,Nodejs 會將 module.exports 的值賦於全域性變數 exports ,以便 module.exports.f = ... 可以更簡潔的寫成 exports.f = ... 。注意:就像所有變數一樣,如果重新給 exports 賦值,它就不再繫結到 module.exports 了,也不會匯出指定模組

 

3,require的機制

假設Y是路徑,X是檔名或目錄名,當 Nodejs 遇到 require(Y+X) 時,按照下面的順序處理:

  1、如果 X 是核心模組)內建模組之間從記憶體載入

           a.返回該模組(例如:require("http")

           b.不再繼續執行

  2、如果Y是以“./”、“/”或“../”開頭(相對路徑和絕對路徑則被認為是檔案模組)

           a.把X當成檔案,從指定路徑開始,依次查詢下面檔案:X、X.js、X.json、X.node,只要其中一個存在,就返回該檔案,不再繼續執行

         b.把X當成目錄,從指定路徑開始,依次查詢下面檔案:X/package.json(main欄位)、X/index.js、X/index.json、X/index.node,只要其中一個存在,就返回該檔案,不再繼續執行

  3、npm安裝的第三方模組,一個包

               如果 X 不是核心模組,也沒有以“./”、“/”或“../”開頭,則Nodejs會從當前模組的父目錄開始,嘗試從它的 /node_module 目錄里加載模組,如果還是沒有找到,則移動到再上一層父目錄,直到檔案系統的根目錄

  4.丟擲“not found”

 

4,import和require的區別

        ES6標準釋出後,module成為標準,標準的使用是以export指令(對外輸出本模組)匯出介面,以import引入模組,但是在我們一貫的node模組中,我們採用的是CommonJS規範,使用require引入模組,使用module.exports匯出介面。

        ES6在語言規格的層面上,實現了模組功能,而且實現得相當簡單,完全可以取代現有的CommonJS和AMD規範,成為瀏覽器和伺服器通用的模組解決方案。

        import的語法跟require不同,而且import必須放在檔案的最開始,且前面不允許有其他邏輯程式碼

import $ from 'jquery';
import * as _ from '_';
import {a,b,c} from './a';
import {default as alias, a as a_a, b, c} from './a';

        require的使用非常簡單,它相當於module.exports的傳送門,module.exports後面的內容是什麼,require的結果就是什麼,物件、數字、字串、函式……再把require的結果賦值給某個變數,相當於把require和module.exports進行平行空間的位置重疊。使用時,完全可以忽略模組化這個概念來使用require,僅僅把它當做一個node內建的全域性函式,它的引數甚至可以是表示式

require('./a')(); // a模組是一個函式,立即執行a模組函式
var data = require('./a').data; // a模組匯出的是一個物件
var a = require('./a')[0]; // a模組匯出的是一個數組

 

5,node非同步程式設計I/0和事件迴圈

        Node.js 非同步程式設計的直接體現就是回撥。回撥函式在完成任務後就會被呼叫,Node 使用了大量的回撥函式,Node 所有 API 都支援回撥函式。

        我們可以一邊讀取檔案,一邊執行其他命令,在檔案讀取完成後,我們將檔案內容作為回撥函式的引數返回。這樣在執行程式碼時就沒有阻塞或等待檔案 I/O 操作。這就大大提高了 Node.js 的效能,可以處理大量的併發請求。

        Node.js 是單程序單執行緒應用程式,但是通過事件和回撥支援併發,所以效能非常高。Node.js 的每一個 API 都是非同步的,並作為一個獨立執行緒執行,使用非同步函式呼叫,並處理併發。

        Node.js 基本上所有的事件機制都是用設計模式中觀察者模式實現。Node.js 單執行緒類似進入一個while(true)的事件迴圈,直到沒有事件觀察者退出,每個非同步事件都生成一個事件觀察者,如果有事件發生就呼叫該回調函式.

 

6,nodejs事件系統 Node.js EventEmitter

        Node.js 所有的非同步 I/O 操作在完成時都會發送一個事件到事件佇列。EventEmitter 物件如果在例項化時發生錯誤,會觸發 error 事件。當新增新的監聽器時,newListener 事件會觸發,當監聽器被移除時,removeListener 事件被觸發。

// 引入 events 模組
var events = require('events');
// 建立 eventEmitter 物件
var eventEmitter = new events.EventEmitter();

方法:

       1,addListener(event, listener) 為指定事件新增一個監聽器到監聽器陣列的尾部。

       2,on(event, listener) 為指定事件註冊一個監聽器,接受一個字串 event 和一個回撥函式。

       3,removeListener(event, listener) 移除指定事件的某個監聽器,監聽器必須是該事件已經註冊過的監聽器。它接受兩個引數,第一個是事件名稱,第二個是回撥函式名稱。

        4,removeAllListeners([event]) 移除所有事件的所有監聽器, 如果指定事件,則移除指定事件的所有監聽器

        5, listeners(event) 返回指定事件的監聽器陣列。

        6,emit(event, [arg1], [arg2], [...]) 按引數的順序執行每個監聽器,如果事件有註冊監聽返回 true,否則返回 false。

 

7,nodejs檔案系統

        非同步和同步:Node.js 檔案系統(fs 模組)模組中的方法均有非同步和同步版本,例如讀取檔案內容的函式有非同步的 fs.readFile() 和同步的 fs.readFileSync()。非同步的方法函式最後一個引數為回撥函式,回撥函式的第一個引數包含了錯誤資訊(error)。

方法:

       1、開啟檔案 fs.open(path, flags[, mode], callback)

       2、獲取檔案資訊 fs.stat(path, callback)

        3、寫入檔案 fs.writeFile(file, data[, options], callback)

        4、讀取檔案 fs.read(fd, buffer, offset, length, position, callback)

             引數使用說明如下:

                     fd - 通過 fs.open() 方法返回的檔案描述符。

                     buffer - 資料寫入的緩衝區。

                     offset - 緩衝區寫入的寫入偏移量。

                     length - 要從檔案中讀取的位元組數。

                     position - 檔案讀取的起始位置,如果 position 的值為 null,則會從當前檔案指標的位置讀取。

                    callback - 回撥函式,有三個引數err, bytesRead, buffer,err 為錯誤資訊, bytesRead 表示讀取的位元組數,buffer 為緩衝區物件。

        5、關閉檔案 fs.close(fd, callback)

        6、擷取檔案 fs.ftruncate(fd, len, callback)

        7、刪除檔案 fs.unlink(path, callback)

        8、建立目錄 fs.mkdir(path[, mode], callback)

        9、讀取目錄 fs.readdir(path, callback)

        10、刪除目錄 fs.rmdir(path, callback)

 

8、Node.js Stream(流)

        Stream 是一個抽象介面,Node 中有很多物件實現了這個介面。例如,對http 伺服器發起請求的request 物件就是一個 Stream,還有stdout(標準輸出)。

        所有的 Stream 物件都是 EventEmitter 的例項。常用的事件有:

               data - 當有資料可讀時觸發。

               end - 沒有更多的資料可讀時觸發。

               error - 在接收和寫入過程中發生錯誤時觸發。

               finish - 所有資料已被寫入到底層系統時觸發。

1、建立可讀流

               var readerStream = fs.createReadStream('input.txt');

2、建立一個可以寫入的流,寫入到檔案 output.txt 中

               var writerStream = fs.createWriteStream('output.txt');

3、管道讀寫操作,讀取 input.txt 檔案內容,並將內容寫入到 output.txt 檔案中

               readerStream.pipe(writerStream);

4、壓縮 input.txt 檔案為 input.txt.gz,鏈式流

               fs.createReadStream('input.txt').pipe(zlib.createGzip()).pipe(fs.createWriteStream('input.txt.gz'));

5、解壓 input.txt.gz 檔案為 input.txt

               fs.createReadStream('input.txt.gz').pipe(zlib.createGunzip()).pipe(fs.createWriteStream('input.txt'));

 

9、Node.js 全域性物件

       JavaScript 中有一個特殊的物件,稱為全域性物件(Global Object),它及其所有屬性都可以在程式的任何地方訪問,即全域性變數。

          1、__filename __filename 表示當前正在執行的指令碼的檔名。它將輸出檔案所在位置的絕對路徑,且和命令列引數所指定的檔名不一定相同。 如果在模組中,返回的值是模組檔案的路徑。

           2、__dirname __dirname 表示當前執行指令碼所在的目錄。

          3、setTimeout(cb, ms) setTimeout(cb, ms) 全域性函式在指定的毫秒(ms)數後執行指定函式(cb)。:setTimeout() 只執行一次指定函式。返回一個代表定時器的控制代碼值。

        4、clearTimeout(t) clearTimeout( t ) 全域性函式用於停止一個之前通過 setTimeout() 建立的定時器。 引數 t 是通過 setTimeout() 函式建立的定時器。

           5、setInterval(cb, ms) setInterval(cb, ms) 全域性函式在指定的毫秒(ms)數後執行指定函式(cb)。

返回一個代表定時器的控制代碼值。可以使用 clearInterval(t) 函式來清除定時器。setInterval() 方法會不停地呼叫函式,直到 clearInterval() 被呼叫或視窗被關閉。

           6、console console 用於提供控制檯標準輸出,它是由 Internet Explorer 的 JScript 引擎提供的除錯工具,後來逐漸成為瀏覽器的實施標準。

           7、process process 是一個全域性變數,即 global 物件的屬性。它用於描述當前Node.js 程序狀態的物件,提供了一個與作業系統的簡單介面。重要屬性包括標準輸入輸出流stdin和stdout