摘要:先天就缺乏一項(xiàng)功能模塊通過標(biāo)簽引入代碼的方式顯得雜亂無章,語言自身毫無組織和約束能力。與文件模塊區(qū)別地方在于它從內(nèi)存中加載緩存執(zhí)行結(jié)果的位置核心模塊在對(duì)象上,文件模塊在對(duì)象上未完待續(xù)
javascript先天就缺乏一項(xiàng)功能:模塊
javasciprt 通過script標(biāo)簽引入代碼的方式顯得雜亂無章,語言自身毫無組織和約束能力。人們不得不用命名空間等方式人為地約束代碼,以求達(dá)到安全和易用的目的。
為了讓javascript能在服務(wù)端有市場(chǎng),社區(qū)為javascript制定了相應(yīng)的規(guī)范——CommonJS
CommonJS規(guī)范 CommonJs的出發(fā)點(diǎn)javascript有以下缺點(diǎn):
==沒有模塊系統(tǒng)==
==標(biāo)準(zhǔn)庫(kù)較少==-比如沒有文件系統(tǒng)、I/O流等標(biāo)準(zhǔn)的API
==沒有標(biāo)準(zhǔn)接口==-幾乎沒有定義過web服務(wù)器或者數(shù)據(jù)庫(kù)之類的標(biāo)準(zhǔn)統(tǒng)一接口
==缺乏包管理系統(tǒng)==-javascript沒有自動(dòng)加載和安裝依賴的能力
CommonJS就是來彌補(bǔ)這些缺陷的
CommonJS大部分規(guī)范依舊是草案,但是為javascript開發(fā)大型應(yīng)用程序指明了一條道路
Node受到CommonJS的影響,CommonJS因Node表現(xiàn)優(yōu)異而走入各個(gè)公司項(xiàng)目里,相互影響和促進(jìn)
CommonJS的模塊規(guī)范分為模塊引用、模塊定義、模塊標(biāo)識(shí)
==模塊引用== var math = require("math");
es6已更新一套支持模塊引用的語法:import。在調(diào)用require時(shí),可以把它放在某個(gè)判斷條件下,但import不行;在打包編譯時(shí),如果require里的文件模塊不存在,即便邏輯上不會(huì)進(jìn)入其所在的判斷條件,依舊會(huì)報(bào)錯(cuò)??梢允褂胻ry{}catch(e){}來處理
==模塊定義==
提供了exports對(duì)象用于導(dǎo)出當(dāng)前模塊的方法或變量
export 是es6的規(guī)范,與import一同用,不要弄混了
一個(gè)模塊里還有module對(duì)象,代表模塊自身;exports是module的屬性
在Node中,一個(gè)文件就是一個(gè)模塊,將方法掛載在exports對(duì)象上作為屬性即可定義導(dǎo)出的方式
// math.js
exports.add = function(a,b){
return a+b;
}
exports.sum = function(a,b){
return a+b;
}
// index.js
var math = reqire("math");
exports.add = function(val){
return math.add(val,1);
}
==模塊標(biāo)識(shí)==
指的是傳給require()方法的參數(shù),必須是符合小駝峰命名的字符串,或者以.、..開頭的相對(duì)路徑,或者絕對(duì)路徑
每個(gè)模塊具有獨(dú)立的空間,互不干擾,用戶不必考慮變量污染
Node的模塊實(shí)現(xiàn)Node沒有完全按照CommonJS規(guī)范實(shí)現(xiàn),做了一定的取舍并加入自身需要的特性。
Node引入模塊需經(jīng)歷如下3個(gè)步驟
==路徑分析==
==文件定位==
==編譯執(zhí)行==
Node中模塊分為兩塊:一類是Node提供的模塊,稱為==核心模塊==;另一類是用戶編寫的模塊,稱為==文件模塊==
核心模塊在編譯過程中,成為二進(jìn)制執(zhí)行文件;Node進(jìn)程啟動(dòng)時(shí),部分核心模塊就直接加載進(jìn)內(nèi)存中
開發(fā)者引入這部分核心模塊時(shí),省略了文件定位、編譯執(zhí)行,且在路徑分析中優(yōu)先判斷;故,加載速度最快
文件模塊是在運(yùn)行時(shí)動(dòng)態(tài)加載,需要路徑分析、文件定位、編譯執(zhí)行過程,速度比核心模塊慢
先路徑分析文件定位、最后再運(yùn)行,所以前面require一個(gè)不存在的文件時(shí),即便有判斷條件,依然會(huì)報(bào)錯(cuò)
優(yōu)先從緩存加載Node對(duì)引入過的模塊都會(huì)進(jìn)行緩存,以減少二次引入時(shí)的開銷。==Node緩存的是編譯和執(zhí)行之后的對(duì)象==
所以,所有模塊exports/export出的的東西,在內(nèi)存中有且僅有一份,不受exports/export后的表達(dá)式/new之類的語句所影響
require()方法/import語句對(duì)于相同模塊的二次加載都一律采用緩存優(yōu)先的方式,這是第一優(yōu)先級(jí)的。核心模塊的緩存檢查優(yōu)于文件模塊的緩存檢查
路徑分析和文件定位因標(biāo)識(shí)符的不同形式,模塊的查找和定位有不同程度的差異
模塊標(biāo)識(shí)符分析
標(biāo)識(shí)符分為以下幾類:
==核心模塊==,如http、fs、path
.或..開始的==相對(duì)路徑文件模塊==
以/開始的==絕對(duì)路徑文件模塊==
==非路徑形式的文件模塊==
核心模塊
優(yōu)先級(jí)僅次于緩存加載,加載速度最快
不能將自定義模塊的標(biāo)識(shí)符與核心模塊標(biāo)識(shí)符定義得一致,除非你換用路徑的方式
路徑形式的文件模塊
. .. /開始的標(biāo)識(shí)符,均視為文件模塊
require將路徑轉(zhuǎn)為真實(shí)路徑,以此做索引,編譯執(zhí)行后的結(jié)果放入緩存
加載速度比核心模塊慢
自定義模塊
特殊的文件模塊,查找費(fèi)時(shí),加載速度最慢
“模塊路徑”——Node定位文件模塊時(shí)定制的查找策略。模塊路徑是一個(gè)路徑組成的數(shù)組:
[
?當(dāng)前文件目錄下的xx目錄,
?父目錄下的xx目錄,
?父目錄下的父目錄下的xx目錄,
?沿路徑向上逐級(jí)遞歸,直到根目錄下的xx目錄
]
類似于js的原型鏈或作用域鏈的查找方式。也正因如此,一旦路徑越深,查找耗時(shí)就越多,所以加載速度最慢
文件定位
有緩存的存在和前面的路徑分析,文件定位相對(duì)比較簡(jiǎn)單。這里注意一些細(xì)節(jié):
文件擴(kuò)展名分析
有時(shí)標(biāo)識(shí)符沒有擴(kuò)展名,CommonJS規(guī)范不允許不包含文件擴(kuò)展名,但Node會(huì)按.js、.json、.node的順序依次嘗試
嘗試時(shí),會(huì)調(diào)用fs模塊同步阻塞時(shí)判斷文件是否存在。由于Node單線程,所以這里會(huì)引起性能問題——建議.node/.json文件加上擴(kuò)展名
目錄分析和包
有時(shí)沒查找到文件,而是一個(gè)目錄
Node會(huì)先找當(dāng)前目錄下的package.json,解析出main屬性指定的文件名進(jìn)行定位;如果文件名沒有擴(kuò)展名,則會(huì)進(jìn)入擴(kuò)展名分析的步驟
解析方式就是JSON.parse()
如果main提供的文件名有誤,或者沒有package.json,則查index(.js、.json、.json)
還沒定位成功,則按照自定義模塊的模塊路徑 策略,去父目錄查詢;如果模塊路徑數(shù)組遍歷完畢都沒找到,則拋出查找失敗的異常
模塊編譯(這里指的都是文件模塊,非核心模塊) 當(dāng)定位到具體文件后,Node會(huì)新建一個(gè)模塊對(duì)象,將文件載入并編譯。載入方法根據(jù)不同文件擴(kuò)展名而區(qū)分
.js文件:fs模塊同步讀取后編譯執(zhí)行
.node文件:這是c/c++編寫的擴(kuò)展文件,通過dlopen()方法加載最后編譯生成的文件
.json文件:fs模塊同步讀取后用JSON.parse()解析返回結(jié)果
其余擴(kuò)展名:當(dāng).js文件載入
編譯成功的模塊會(huì)緩存在Module._cache上,以文件路徑作為索引
javascript模塊的編譯
編譯過程中,Node對(duì)獲取的javascript的文件內(nèi)容進(jìn)行了頭尾包裝,頭部添加(function(==exports, require, module, __filename, __dirname==){ ,尾部添加 })
__filename 完整的文件路徑;__dirname 文件目錄
包裝后的代碼vm原生模塊的runInThisContext()執(zhí)行,返回一個(gè)具體的function對(duì)象
最后,將當(dāng)前模塊對(duì)象的exports、require()、module、文件路徑和目錄作為參數(shù)傳入給function對(duì)象
執(zhí)行后exports返回給調(diào)用方,其上的任何方法與屬性均可被外部調(diào)用,但是模塊中的其余變量或?qū)傩圆豢伞?=以此達(dá)到模塊間的作用域隔離==
這就是Node對(duì)CommonJS模塊規(guī)范的實(shí)現(xiàn)
exports的誤用 編寫代碼時(shí),理論上只要這樣寫就行:
exports = function(){//My Class};
但是這樣寫是有問題的,我們來看看編譯過程:
頭尾包裝:
(function(exports, require, module, __filename, __dirname){
exports = function(){//My Class};
})
看,你把形參改了。。。但是exports最后是要返回給調(diào)用方然后被外部調(diào)用的,==改形參根本不能真正改變exports對(duì)象的內(nèi)容==
所以,要不老老實(shí)實(shí)地寫:exports.add = ...;或者寫module.exports = ...
c/c++模塊的編譯
事實(shí)上,.node模塊不需要編譯,因?yàn)樗莄/c++模塊之后編譯生成。它只需要加載和執(zhí)行
執(zhí)行中exports對(duì)象與.node模塊產(chǎn)生臉型,返回給調(diào)用者
優(yōu)勢(shì):執(zhí)行效率高;劣勢(shì):編寫門檻高
JSON文件的編譯
fs模塊同步讀取JSON文件
JSON.parse()方法得到對(duì)象
賦給exports
如果.json文件作為配置文件(如package.json),則不必調(diào)用fs模塊去讀取和解析,直接reqire()引入即可。同理它也是享受緩存的便利,二次引入時(shí)沒有性能影響
核心模塊分為c/c++編寫的和javascript編寫的兩部分
js核心模塊的編譯過程編譯程序會(huì)將js模塊文件編譯成c/c++代碼
轉(zhuǎn)存為c/c++代碼
將所有內(nèi)置的js代碼轉(zhuǎn)換成c++的數(shù)組,此時(shí)js代碼不可直接執(zhí)行,啟動(dòng)Node進(jìn)程后,js代碼直接加載進(jìn)內(nèi)存,將來查找比文件模塊要快得多
編譯js核心模塊
經(jīng)歷頭尾包裝、執(zhí)行、導(dǎo)出exports對(duì)象。與文件模塊區(qū)別地方在于:它從內(nèi)存中加載;緩存執(zhí)行結(jié)果的位置
核心模塊在NativeModule._cache對(duì)象上,文件模塊在Module._cache對(duì)象上
(未完待續(xù)~)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/7211.html
摘要:垃圾回收內(nèi)存管理實(shí)踐先通過一個(gè)來看看在中進(jìn)行垃圾回收的過程是怎樣的內(nèi)存泄漏識(shí)別在環(huán)境里提供了方法用來查看當(dāng)前進(jìn)程內(nèi)存使用情況,單位為字節(jié)中保存的進(jìn)程占用的內(nèi)存部分,包括代碼本身?xiàng)6选? showImg(https://segmentfault.com/img/remote/1460000019894672?w=640&h=426);作者 | 五月君Node.js 技術(shù)棧 | https:...
摘要:它是在的基礎(chǔ)上改進(jìn)的一種方案,通過對(duì)文件描述符上的事件狀態(tài)進(jìn)行判斷。檢索新的事件執(zhí)行與相關(guān)的回調(diào)幾乎所有情況下,除了關(guān)閉的回調(diào)函數(shù),它們由計(jì)時(shí)器和排定的之外,其余情況將在此處阻塞。執(zhí)行事件的,例如或者。 前言 學(xué)習(xí)Node就繞不開異步IO, 異步IO又與事件循環(huán)息息相關(guān), 而關(guān)于這一塊一直沒有仔細(xì)去了解整理過, 剛好最近在做項(xiàng)目的時(shí)候, 有了一些思考就記錄了下來, 希望能盡量將這一塊的...
摘要:插件開發(fā)前端掘金作者原文地址譯者插件是為應(yīng)用添加全局功能的一種強(qiáng)大而且簡(jiǎn)單的方式。提供了與使用掌控異步前端掘金教你使用在行代碼內(nèi)優(yōu)雅的實(shí)現(xiàn)文件分片斷點(diǎn)續(xù)傳。 Vue.js 插件開發(fā) - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins譯者:jeneser Vue.js插件是為應(yīng)用添加全局功能的一種強(qiáng)大而且簡(jiǎn)單的方式。插....
摘要:概述本文主要介紹了我對(duì)的一些核心特性的理解,包括架構(gòu)特點(diǎn)機(jī)制核心模塊與簡(jiǎn)單應(yīng)用。在此期間,主線程繼續(xù)執(zhí)行其他任務(wù)。延續(xù)了瀏覽器端單線程,只用一個(gè)主線程執(zhí)行,不斷循環(huán)遍歷事件隊(duì)列,執(zhí)行事件。 原文地址在我的博客,轉(zhuǎn)載請(qǐng)注明來源,謝謝! node是在前端領(lǐng)域經(jīng)常看到的詞。node對(duì)于前端的重要性已經(jīng)不言而喻,掌握node也是作為合格的前端工程師一項(xiàng)基本功了。知道node、知道后端的一些東西...
摘要:前端每周清單專注前端領(lǐng)域內(nèi)容,以對(duì)外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn)分為新聞熱點(diǎn)開發(fā)教程工程實(shí)踐深度閱讀開源項(xiàng)目巔峰人生等欄目。對(duì)該漏洞的綜合評(píng)級(jí)為高危。目前,相關(guān)利用方式已經(jīng)在互聯(lián)網(wǎng)上公開,近期出現(xiàn)攻擊嘗試爆發(fā)的可能。 前端每周清單專注前端領(lǐng)域內(nèi)容,以對(duì)外文資料的搜集為主,幫助開發(fā)者了解一周前端熱點(diǎn);分為新聞熱點(diǎn)、開發(fā)教程、工程實(shí)踐、深度閱讀、開源項(xiàng)目、巔峰人生等欄目。歡...
閱讀 3208·2021-11-25 09:43
閱讀 3418·2021-11-11 16:54
閱讀 844·2021-11-02 14:42
閱讀 3773·2021-09-30 09:58
閱讀 3677·2021-09-29 09:44
閱讀 1291·2019-08-30 15:56
閱讀 2109·2019-08-30 15:54
閱讀 2996·2019-08-30 15:43