深入理解Node.js 的 API 設計的源頭:POSIX
如果你用過 Node.js 的 api,會不會覺得奇怪,為什么 api 的名字是這樣的:
比如創建目錄:
- const fs = require('fs');
- fs.mkdir('/a/b/c', { recursive: true }, (err) => {
- if (err) throw err;
- });
創建進程:
- const childProcess = require('child_process');
- childProcess.fork('a/b/c.js');
- childProcess.execFile('a/b/dddd');
- childProcess.exec('"/path/to/test file/test.sh" arg1 arg2');
- childProcess.spawn('ls', ['-lh', '/usr']);
mkdir、fork、exec、spawn 等,這些名字是怎么起的?
如果你用過 linux 命令或者 c 的函數庫,你會發現這些 api 在命令和 c 函數庫中也都是這個名字。
為什么會這樣呢?這些 api 是什么標準么?
沒錯,這就是 POSIX 標準
POSIX 是什么
POSIX 是 portable operating system interface (可移植的操作系統接口)的縮寫,x 是 unix 的意思,也就是從 unix 繼承而來。
因為不同操作系統如果提供的函數和系統調用不一樣,那么基于操作系統的上層應用程序的源代碼就不一樣,這就導致了一個平臺寫的代碼沒法在另一個平臺上編譯。
怎么辦呢?
如果每個操作系統提供的 api 一樣呢?不管操作系統底層怎么實現這些能力的,只要暴露出同樣的 api 給應用程序即可,這樣源代碼是跨平臺的,在不同的操作系統上編譯之后就能跑起來。
這個統一操作系統暴露的 api 的標準就是 POSIX。
可以把這個 POSIX 標準理解為 ts 里面定義的一個 interface,只要實現了這個 interface 的 api 就是兼容 POSIX 標準的。
POSIX 最早是 unix 擴展而來,linux 實現了這個 POSIX 的標準,而后來 windows 迫于壓力,也不得不兼容了 POSIX 標準,不然很多 linux 的應用程序在 windows 上就跑不起來。我們常用的 osx 也是。
所以說,POSIX 是操作系統向上層應用提供能力的一些標準接口,包括系統調用、c 函數庫、shell 命令。
- 所謂的標準是指被 ISO 國際標準化組織承認的,這是一個國際組織,成員遍布各個國家,是制定各種國際標準的組織。POSIX 就是 ISO/IEC 9945 標準(IEC 是電子方向的標準化組織)。其實 POSIX 是 IEEE 提出來的,這是一個美國的標準化組織,他提出的標準被 ISO 承認會成為國際標準,比如 POSIX 就是他們提出的 IEEE Std 1003 標準,現在被 ISO 承認,成為了 ISO/IEC 9945 標準。
POSIX 有哪些內容
我們來看一下支持 posix 的 linux 提供了哪些系統調用(系統調用指的是在內核代碼中提供的程序):
進程控制:
- fork 創建一個新進程
- execv 運行可執行文件
- exit 中止進程
文件讀寫
- open 打開文件
- close 關閉文件描述符
- write 寫文件
- read 讀文件
- truncate 截斷文件
- fsync 把文件在內存的部分寫入磁盤
文件系統相關
- access 確定文件是否可存取
- chdir 改變當前工作目錄
- chown 改變文件的屬主或者用戶組
- stat 取文件狀態信息
- mkdir 創建目錄
- symlink 創建符號鏈接
- unlink 刪除鏈接
等
這些系統調用很多在 Node.js 里有同名的 api,shell 也有同名的命令:
比如:
- fs.stats
- fs.access
- fs.chown
- fs.mkdir
- fs.open
- fs.close
- fs.read
- fs.write
- child_process.fork
- child_process.exec
- child_process.execFile
等
Node.js api 的特點
Node.js 是一個 js 的運行時,基于 v8 來注入很多提供操作系統能力的 api 給 js 調用,而這些 api 的設計很多都是直接用的 POSIX 標準的 api 名字,沒有做很多抽象。
Java 的 JRE(java runtime) 也提供了操作系統能力的抽象,但是那些 api 卻和操作系統 POSIX 的 api 關系不大,而且融入了很多設計模式的東西,比如 io 流的裝飾器模式。
Node.js 的 api 的特點就是抽象并不多,而且很多 api 名字和 linux 命令都很像,貼近 POSIX 標準。所以學習 Node.js 的時候還是要學習下 linux 命令的,這兩者在設計上有一定的關系。
總結
POSIX 標準是操作系統能力的標準,定義了操作系統應該暴露什么 api 給應用程序,包括 shell 命令、c 函數庫、系統調用等標準。POSIX 標準使得應用程序在源碼層面是可以跨平臺移植的,分別在不同平臺做編譯即可。
POSIX 是 ISO 承認的國際化標準,最早是由美國的一個標準協會 IEEE 提出的。ISO 是專門定制國際標準的組織,有很多國家的成員參與。
Node.js 的 api 并沒有做很多抽象,名字也很大部分和 POSIX 標準的 api 比較像,這是它的特點,相比之下,JRE 暴露給 java 的 api 則做了很多抽象。
因為 Node.js 的 api 很多和 c 函數庫、shell 命令比較接近,所以學習 Node.js 結合學習 shell 命令,或者會 c 的可以再學下系統的函數庫會有更多的收獲。
了解 POSIX,是理解 Node.js api 設計,學好 Node.js 的前提。