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

        深入了解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號
        主站蜘蛛池模板: 久久婷婷国产综合精品| 国产成人久久精品区一区二区| 国产成人亚洲综合无码精品| 国产精品福利在线观看免费不卡| 国产AV午夜精品一区二区三区 | 日韩人妻精品无码一区二区三区| 国产欧美日韩综合精品一区二区三区| 福利姬在线精品观看| 欧美亚洲色综久久精品国产| 日韩精品国产自在欧美| 国产欧美日本精品| 91精品国产自产在线观看| 国产精品爽黄69天堂a| 成人区精品一区二区不卡 | 亚洲午夜国产精品无码| 免费精品精品国产欧美在线欧美高清免费一级在线 | 国产亚洲午夜高清国产拍精品| 久久最新精品国产| 国内精品在线视频| 国产精品免费观看| 国产精品久久久久9999| 国产福利91精品一区二区| 国产成人精品日本亚洲| 国内精品久久久久影院优| 久久久精品人妻一区二区三区蜜桃| 婷婷国产成人精品视频| 最新精品国偷自产在线| 中文字幕精品亚洲无线码一区应用 | 国产精品VA在线观看无码不卡 | 国产精品99久久久久久猫咪| 精品国产免费一区二区三区香蕉| 国产AV无码专区亚洲精品| 99re久久精品国产首页2020| 99re这里只有精品6| 国产精品一区二区久久精品| 久久99精品国产99久久6男男| 欧美激情精品久久久久| 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 99久久精品国产综合一区| 自怕偷自怕亚洲精品| 99国内精品久久久久久久|