站長資訊網
        最全最豐富的資訊網站

        深入了解Node.js中的VM模塊

        VM模塊是NodeJS里面的核心模塊,支撐了require方法和NodeJS的運行機制,我們有些時候可能也要用到VM模板來做一些特殊的事情。本篇文章就來帶大家詳細了解下Node中的VM模塊,希望對大家有所幫助!

        深入了解Node.js中的VM模塊

        參考文獻 vm 虛擬機 | Node 官網

        http://nodejs.cn/api/vm.html

        在上一篇文章中,我們提到了一個問題。

        字符串如何能變成 JS 執行呢?

        我們詳細介紹了兩種方法,分別是 eval函數 和 new Function 。

        在這里我們需要再強調一下, 由 Function 構造器創建的函數不會創建當前環境的閉包,它們總是被創建于全局環境,因此在運行時它們只能訪問全局變量和自己的局部變量,不能訪問它們被 Function 構造器創建時所在的作用域的變量。這一點與使用 eval 執行創建函數的代碼不同。

        global.a = 100; // 掛在到全局對象global上 var b = 200; // this !== global new Function("console.log(a)")() // 100 new Function("console.log(b)")() // b is not defined

        Function 可以獲取全局變量,所以他還是可能會有變量污染的情況出現。Function模塊引擎的實現原理 ,后續我會出一篇文章進行單獨講解。

        還有一種解決方案,我們在上一次文章中沒有進行詳細的展開,那就是 vm模塊

        vm模塊

        在上述文字中,我一直在強調一個概念,那就是 變量的污染

        VM的特點就是不受環境的影響,也可以說他就是一個 沙箱環境 (沙箱模式給模塊提供一個環境運行而不影響其它模塊和它們私有的沙箱)

        const vm = require('vm') global.a = 100; // 運行在當前環境中[當前作用域] vm.runInThisContext('console.log(a)'); // 100 // 運行在新的環境中[其他作用域] vm.runInNewContext('console.log(a)'); // a is not defined

        在這里我們要強調一下,因為 在Node.js中全局變量是在多個模塊下共享的,所以盡量不要在global中定義屬性。 Demo中的定義是為了方便理解。

        假設我們在同級目錄下有一個文件 1.js ,里面定義了 global.a = 100;。 現在我們引入這個文件

        requrie(./1); console.log(a); // 100

        我們可以發現,在當前文件中我們并沒有定義變量a,僅僅只是把兩個模塊文件關聯在了一起。這就是我上面提到的,Node中全局變量是在多個模塊下共享的。

        他的原理是因為在 Node 的環境中,全局中有一個執行上下文。

        // 模擬一下Node的全局環境 // vm.runInThisContext在當前全局環境執行,但不會產生新函數 - function(exports, module, require, __dirname, __filename){ // ... } - vm.runInThisContext ... // vm.runInNewContext在全局環境之外執行 vm.runInNewContext ...

        所以,vm.runInThisContext 可以訪問到 global上的全局變量,但是訪問不到自定義的變量。而 vm.runInNewContext 訪問不到 global,也訪問不到自定義變量,他存在于一個全新的執行上下文。

        而我們require 就是通過 vm.runInThisContext 實現的。

        實現require 主要可以分為以下四步。

        • 讀取需要引入的文件。

        • 讀取到文件后,將代碼封裝成一個函數。

        • 通過 vm.runInThisContext 將他轉變成 JS 語法。

        • 代碼調用。

        假設我們現在有以下兩個文件。分別是 a.jsb.js

        // 文件a通過module.exports導出一個變量,在文件b中使用require進行接收。 // a.js module.exports = "a" // b.js let a = require('./a'); console.log(a); // a

        我們可以通過上面的四個步驟,分析一下導入導出的實現邏輯是什么樣的。

        • 讀取文件。

          將需要引入的文件內容引入到需要接收的文件里,就會變成這個樣子

          let a = module.exports = "a";

          但是這種形式,Node根本解析不了,所以我們就需要進行第二步。

        • 將讀取的文件封裝成函數。

          let a = (function(exports, module, require, __dirname, __filename){   module.exports = "a";   return module.exports })(...args) // exports, module, require, __dirname, __filename 將五個參數傳入

          封裝成函數的原因,我們可以參考下面這個例子。

          假設我們現在傳入的不是字符串,而是一個函數。

          // a.js var a = 100; module.exports = function(){}

          這樣我們在解析的時候,就會被解析成下面這種格式

          let a = (function(exports, module, require, __dirname, __filename){   var a = 100;   module.exports = function(){};   return module.exports })(...args) // exports, module, require, __dirname, __filename 將五個參數傳入

          我們導出的是 module.exports,所以在模塊文件中定義的變量a,也只屬于當前這個執行上下文。

          在解析的時候,變量a 會被放到函數中。真正的實現了 作用域分離

        • vm.runInThisContext 解析成可執行的Js代碼

          我們處理過的代碼會以字符串的形式存在,所以我們需要通過vm.runInThisContext將字符串進行解析。

        • 進行代碼調用

          在此之前,我們其實還需要對代碼進行調試。

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 亚洲αv在线精品糸列| 久久久久人妻精品一区二区三区| 无码精品人妻一区二区三区AV| 久久成人精品视频| 亚洲精品高清国产一线久久| 国产精品无码免费播放| 国产99视频精品免视看7| 最新国产精品拍自在线播放| 国产精品99久久久久久猫咪| 久久91综合国产91久久精品| 国产亚洲精品无码成人| 亚洲精品夜夜夜妓女网| 四虎国产精品永久地址入口| 久久国产精品波多野结衣AV| 国产精品国产三级在线高清观看| 精品国产一区二区三区久久| 国产成人精品高清在线观看93 | 一本一本久久a久久综合精品蜜桃| 精品成人一区二区三区四区| 91精品国产高清久久久久久国产嫩草| 99国产精品久久久久久久成人热| 午夜精品射精入后重之免费观看 | 国产精品区AV一区二区| 精品一区二区久久| 国产成人精品免费午夜app| 国语自产少妇精品视频| 无码人妻精品一区二区三区66 | 亚洲精品乱码久久久久久中文字幕 | 亚洲国产精品热久久| 国产成人精品高清在线观看99| 精品无码人妻一区二区三区| 久久精品中文騷妇女内射| 精品亚洲成a人片在线观看少妇| 精品欧洲av无码一区二区三区| 精品久久8x国产免费观看| 国产精品久久久久久吹潮| 国产成人精品日本亚洲直接| 久久99热狠狠色精品一区| 青青草原综合久久大伊人精品| 777久久精品一区二区三区无码| 香蕉久久夜色精品国产小说|