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

        深入了解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號
        主站蜘蛛池模板: 伊人精品视频在线| 2022国产精品福利在线观看| 国产美女久久精品香蕉69 | 亚洲爆乳精品无码一区二区| 2021年精品国产福利在线| 国产精品久久影院| 精品欧洲AV无码一区二区男男| 日韩专区亚洲精品欧美专区| 国产精品毛片一区二区| 四虎国产精品永久地址51| 国产福利在线观看精品| 国产精品亚洲а∨无码播放| 亚洲AV无码成人精品区天堂| 国产原创精品视频| 久久ww精品w免费人成| 中文成人无字幕乱码精品区| 欧美激情精品久久久久久| 精品国内自产拍在线观看 | 亚洲精品无码av人在线观看 | 亚洲AV无码成人精品区天堂| 亚洲国产高清精品线久久| 欧美日韩精品系列一区二区三区| 国产在线精品一区二区三区不卡 | 国产精品色视频ⅹxxx| 久久精品国产精品青草| 亚洲国产成人久久精品动漫| 精品久久久久久亚洲| 久久91综合国产91久久精品| 久久er热视频在这里精品| 久久91精品国产91久久小草| 91精品国产91久久久久久青草| 91精品国产高清久久久久久国产嫩草| 四虎精品影院永久在线播放| 亚洲欧美精品伊人久久| 亚洲精品一二区| 精品国产一区二区22| 亚洲国产主播精品极品网红| 亚洲国产另类久久久精品黑人| 熟妇人妻VA精品中文字幕| 国产三级精品三级在线专区1| 99精品视频在线|